PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/objectweb/asm/CodeWriter.java

#
Java | 1766 lines | 968 code | 124 blank | 674 comment | 341 complexity | 971fe39529fb2211270217540e882e0a MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. /***
  2. * ASM: a very small and fast Java bytecode manipulation framework
  3. * Copyright (C) 2000 INRIA, France Telecom
  4. * Copyright (C) 2002 France Telecom
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. * Contact: Eric.Bruneton@rd.francetelecom.com
  21. *
  22. * Author: Eric Bruneton
  23. */
  24. package org.objectweb.asm;
  25. /**
  26. * A {@link CodeVisitor CodeVisitor} that generates Java bytecode instructions.
  27. * Each visit method of this class appends the bytecode corresponding to the
  28. * visited instruction to a byte vector, in the order these methods are called.
  29. */
  30. public class CodeWriter implements CodeVisitor {
  31. /**
  32. * <tt>true</tt> if preconditions must be checked at runtime or not.
  33. */
  34. final static boolean CHECK = false;
  35. /**
  36. * Next code writer (see {@link ClassWriter#firstMethod firstMethod}).
  37. */
  38. CodeWriter next;
  39. /**
  40. * The class writer to which this method must be added.
  41. */
  42. private ClassWriter cw;
  43. /**
  44. * The constant pool item that contains the name of this method.
  45. */
  46. private Item name;
  47. /**
  48. * The constant pool item that contains the descriptor of this method.
  49. */
  50. private Item desc;
  51. /**
  52. * Access flags of this method.
  53. */
  54. private int access;
  55. /**
  56. * Maximum stack size of this method.
  57. */
  58. private int maxStack;
  59. /**
  60. * Maximum number of local variables for this method.
  61. */
  62. private int maxLocals;
  63. /**
  64. * The bytecode of this method.
  65. */
  66. private ByteVector code = new ByteVector();
  67. /**
  68. * Number of entries in the catch table of this method.
  69. */
  70. private int catchCount;
  71. /**
  72. * The catch table of this method.
  73. */
  74. private ByteVector catchTable;
  75. /**
  76. * Number of exceptions that can be thrown by this method.
  77. */
  78. private int exceptionCount;
  79. /**
  80. * The exceptions that can be thrown by this method. More
  81. * precisely, this array contains the indexes of the constant pool items
  82. * that contain the internal names of these exception classes.
  83. */
  84. private int[] exceptions;
  85. /**
  86. * Number of entries in the LocalVariableTable attribute.
  87. */
  88. private int localVarCount;
  89. /**
  90. * The LocalVariableTable attribute.
  91. */
  92. private ByteVector localVar;
  93. /**
  94. * Number of entries in the LineNumberTable attribute.
  95. */
  96. private int lineNumberCount;
  97. /**
  98. * The LineNumberTable attribute.
  99. */
  100. private ByteVector lineNumber;
  101. /**
  102. * Indicates if some jump instructions are too small and need to be resized.
  103. */
  104. private boolean resize;
  105. // --------------------------------------------------------------------------
  106. // Fields for the control flow graph analysis algorithm (used to compute the
  107. // maximum stack size). A control flow graph contains one node per "basic
  108. // block", and one edge per "jump" from one basic block to another. Each node
  109. // (i.e., each basic block) is represented by the Label object that
  110. // corresponds to the first instruction of this basic block. Each node also
  111. // stores the list of its successors in the graph, as a linked list of Edge
  112. // objects.
  113. // --------------------------------------------------------------------------
  114. /**
  115. * <tt>true</tt> if the maximum stack size and number of local variables must
  116. * be automatically computed.
  117. */
  118. private final boolean computeMaxs;
  119. /**
  120. * The (relative) stack size after the last visited instruction. This size is
  121. * relative to the beginning of the current basic block, i.e., the true stack
  122. * size after the last visited instruction is equal to the {@link
  123. * Label#beginStackSize beginStackSize} of the current basic block plus
  124. * <tt>stackSize</tt>.
  125. */
  126. private int stackSize;
  127. /**
  128. * The (relative) maximum stack size after the last visited instruction. This
  129. * size is relative to the beginning of the current basic block, i.e., the
  130. * true maximum stack size after the last visited instruction is equal to the
  131. * {@link Label#beginStackSize beginStackSize} of the current basic block plus
  132. * <tt>stackSize</tt>.
  133. */
  134. private int maxStackSize;
  135. /**
  136. * The current basic block. This block is the basic block to which the next
  137. * instruction to be visited must be added.
  138. */
  139. private Label currentBlock;
  140. /**
  141. * The basic block stack used by the control flow analysis algorithm. This
  142. * stack is represented by a linked list of {@link Label Label} objects,
  143. * linked to each other by their {@link Label#next} field. This stack must
  144. * not be confused with the JVM stack used to execute the JVM instructions!
  145. */
  146. private Label blockStack;
  147. /**
  148. * The stack size variation corresponding to each JVM instruction. This stack
  149. * variation is equal to the size of the values produced by an instruction,
  150. * minus the size of the values consumed by this instruction.
  151. */
  152. private final static int[] SIZE;
  153. // --------------------------------------------------------------------------
  154. // Fields to optimize the creation of {@link Edge Edge} objects by using a
  155. // pool of reusable objects. The (shared) pool is a linked list of Edge
  156. // objects, linked to each other by their {@link Edge#poolNext} field. Each
  157. // time a CodeWriter needs to allocate an Edge, it removes the first Edge
  158. // of the pool and adds it to a private list of Edge objects. After the end
  159. // of the control flow analysis algorithm, the Edge objects in the private
  160. // list of the CodeWriter are added back to the pool (by appending this
  161. // private list to the pool list; in order to do this in constant time, both
  162. // head and tail of the private list are stored in this CodeWriter).
  163. // --------------------------------------------------------------------------
  164. /**
  165. * The head of the list of {@link Edge Edge} objects used by this {@link
  166. * CodeWriter CodeWriter}. These objects, linked to each other by their
  167. * {@link Edge#poolNext} field, are added back to the shared pool at the
  168. * end of the control flow analysis algorithm.
  169. */
  170. private Edge head;
  171. /**
  172. * The tail of the list of {@link Edge Edge} objects used by this {@link
  173. * CodeWriter CodeWriter}. These objects, linked to each other by their
  174. * {@link Edge#poolNext} field, are added back to the shared pool at the
  175. * end of the control flow analysis algorithm.
  176. */
  177. private Edge tail;
  178. /**
  179. * The shared pool of {@link Edge Edge} objects. This pool is a linked list
  180. * of Edge objects, linked to each other by their {@link Edge#poolNext} field.
  181. */
  182. private static Edge pool;
  183. // --------------------------------------------------------------------------
  184. // Static initializer
  185. // --------------------------------------------------------------------------
  186. /**
  187. * Computes the stack size variation corresponding to each JVM instruction.
  188. */
  189. static {
  190. int i;
  191. int[] b = new int[202];
  192. String s =
  193. "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDDCDCDEEEEEEEEE" +
  194. "EEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCDCDCEEEEDDDDDDDCDCDCEFEF" +
  195. "DDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFEDDDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
  196. for (i = 0; i < b.length; ++i) {
  197. b[i] = s.charAt(i) - 'E';
  198. }
  199. SIZE = b;
  200. /* code to generate the above string
  201. int NA = 0; // not applicable (unused opcode or variable size opcode)
  202. b = new int[] {
  203. 0, //NOP, // visitInsn
  204. 1, //ACONST_NULL, // -
  205. 1, //ICONST_M1, // -
  206. 1, //ICONST_0, // -
  207. 1, //ICONST_1, // -
  208. 1, //ICONST_2, // -
  209. 1, //ICONST_3, // -
  210. 1, //ICONST_4, // -
  211. 1, //ICONST_5, // -
  212. 2, //LCONST_0, // -
  213. 2, //LCONST_1, // -
  214. 1, //FCONST_0, // -
  215. 1, //FCONST_1, // -
  216. 1, //FCONST_2, // -
  217. 2, //DCONST_0, // -
  218. 2, //DCONST_1, // -
  219. 1, //BIPUSH, // visitIntInsn
  220. 1, //SIPUSH, // -
  221. 1, //LDC, // visitLdcInsn
  222. NA, //LDC_W, // -
  223. NA, //LDC2_W, // -
  224. 1, //ILOAD, // visitVarInsn
  225. 2, //LLOAD, // -
  226. 1, //FLOAD, // -
  227. 2, //DLOAD, // -
  228. 1, //ALOAD, // -
  229. NA, //ILOAD_0, // -
  230. NA, //ILOAD_1, // -
  231. NA, //ILOAD_2, // -
  232. NA, //ILOAD_3, // -
  233. NA, //LLOAD_0, // -
  234. NA, //LLOAD_1, // -
  235. NA, //LLOAD_2, // -
  236. NA, //LLOAD_3, // -
  237. NA, //FLOAD_0, // -
  238. NA, //FLOAD_1, // -
  239. NA, //FLOAD_2, // -
  240. NA, //FLOAD_3, // -
  241. NA, //DLOAD_0, // -
  242. NA, //DLOAD_1, // -
  243. NA, //DLOAD_2, // -
  244. NA, //DLOAD_3, // -
  245. NA, //ALOAD_0, // -
  246. NA, //ALOAD_1, // -
  247. NA, //ALOAD_2, // -
  248. NA, //ALOAD_3, // -
  249. -1, //IALOAD, // visitInsn
  250. 0, //LALOAD, // -
  251. -1, //FALOAD, // -
  252. 0, //DALOAD, // -
  253. -1, //AALOAD, // -
  254. -1, //BALOAD, // -
  255. -1, //CALOAD, // -
  256. -1, //SALOAD, // -
  257. -1, //ISTORE, // visitVarInsn
  258. -2, //LSTORE, // -
  259. -1, //FSTORE, // -
  260. -2, //DSTORE, // -
  261. -1, //ASTORE, // -
  262. NA, //ISTORE_0, // -
  263. NA, //ISTORE_1, // -
  264. NA, //ISTORE_2, // -
  265. NA, //ISTORE_3, // -
  266. NA, //LSTORE_0, // -
  267. NA, //LSTORE_1, // -
  268. NA, //LSTORE_2, // -
  269. NA, //LSTORE_3, // -
  270. NA, //FSTORE_0, // -
  271. NA, //FSTORE_1, // -
  272. NA, //FSTORE_2, // -
  273. NA, //FSTORE_3, // -
  274. NA, //DSTORE_0, // -
  275. NA, //DSTORE_1, // -
  276. NA, //DSTORE_2, // -
  277. NA, //DSTORE_3, // -
  278. NA, //ASTORE_0, // -
  279. NA, //ASTORE_1, // -
  280. NA, //ASTORE_2, // -
  281. NA, //ASTORE_3, // -
  282. -3, //IASTORE, // visitInsn
  283. -4, //LASTORE, // -
  284. -3, //FASTORE, // -
  285. -4, //DASTORE, // -
  286. -3, //AASTORE, // -
  287. -3, //BASTORE, // -
  288. -3, //CASTORE, // -
  289. -3, //SASTORE, // -
  290. -1, //POP, // -
  291. -2, //POP2, // -
  292. 1, //DUP, // -
  293. 1, //DUP_X1, // -
  294. 1, //DUP_X2, // -
  295. 2, //DUP2, // -
  296. 2, //DUP2_X1, // -
  297. 2, //DUP2_X2, // -
  298. 0, //SWAP, // -
  299. -1, //IADD, // -
  300. -2, //LADD, // -
  301. -1, //FADD, // -
  302. -2, //DADD, // -
  303. -1, //ISUB, // -
  304. -2, //LSUB, // -
  305. -1, //FSUB, // -
  306. -2, //DSUB, // -
  307. -1, //IMUL, // -
  308. -2, //LMUL, // -
  309. -1, //FMUL, // -
  310. -2, //DMUL, // -
  311. -1, //IDIV, // -
  312. -2, //LDIV, // -
  313. -1, //FDIV, // -
  314. -2, //DDIV, // -
  315. -1, //IREM, // -
  316. -2, //LREM, // -
  317. -1, //FREM, // -
  318. -2, //DREM, // -
  319. 0, //INEG, // -
  320. 0, //LNEG, // -
  321. 0, //FNEG, // -
  322. 0, //DNEG, // -
  323. -1, //ISHL, // -
  324. -1, //LSHL, // -
  325. -1, //ISHR, // -
  326. -1, //LSHR, // -
  327. -1, //IUSHR, // -
  328. -1, //LUSHR, // -
  329. -1, //IAND, // -
  330. -2, //LAND, // -
  331. -1, //IOR, // -
  332. -2, //LOR, // -
  333. -1, //IXOR, // -
  334. -2, //LXOR, // -
  335. 0, //IINC, // visitIincInsn
  336. 1, //I2L, // visitInsn
  337. 0, //I2F, // -
  338. 1, //I2D, // -
  339. -1, //L2I, // -
  340. -1, //L2F, // -
  341. 0, //L2D, // -
  342. 0, //F2I, // -
  343. 1, //F2L, // -
  344. 1, //F2D, // -
  345. -1, //D2I, // -
  346. 0, //D2L, // -
  347. -1, //D2F, // -
  348. 0, //I2B, // -
  349. 0, //I2C, // -
  350. 0, //I2S, // -
  351. -3, //LCMP, // -
  352. -1, //FCMPL, // -
  353. -1, //FCMPG, // -
  354. -3, //DCMPL, // -
  355. -3, //DCMPG, // -
  356. -1, //IFEQ, // visitJumpInsn
  357. -1, //IFNE, // -
  358. -1, //IFLT, // -
  359. -1, //IFGE, // -
  360. -1, //IFGT, // -
  361. -1, //IFLE, // -
  362. -2, //IF_ICMPEQ, // -
  363. -2, //IF_ICMPNE, // -
  364. -2, //IF_ICMPLT, // -
  365. -2, //IF_ICMPGE, // -
  366. -2, //IF_ICMPGT, // -
  367. -2, //IF_ICMPLE, // -
  368. -2, //IF_ACMPEQ, // -
  369. -2, //IF_ACMPNE, // -
  370. 0, //GOTO, // -
  371. 1, //JSR, // -
  372. 0, //RET, // visitVarInsn
  373. -1, //TABLESWITCH, // visiTableSwitchInsn
  374. -1, //LOOKUPSWITCH, // visitLookupSwitch
  375. -1, //IRETURN, // visitInsn
  376. -2, //LRETURN, // -
  377. -1, //FRETURN, // -
  378. -2, //DRETURN, // -
  379. -1, //ARETURN, // -
  380. 0, //RETURN, // -
  381. NA, //GETSTATIC, // visitFieldInsn
  382. NA, //PUTSTATIC, // -
  383. NA, //GETFIELD, // -
  384. NA, //PUTFIELD, // -
  385. NA, //INVOKEVIRTUAL, // visitMethodInsn
  386. NA, //INVOKESPECIAL, // -
  387. NA, //INVOKESTATIC, // -
  388. NA, //INVOKEINTERFACE, // -
  389. NA, //UNUSED, // NOT VISITED
  390. 1, //NEW, // visitTypeInsn
  391. 0, //NEWARRAY, // visitIntInsn
  392. 0, //ANEWARRAY, // visitTypeInsn
  393. 0, //ARRAYLENGTH, // visitInsn
  394. NA, //ATHROW, // -
  395. 0, //CHECKCAST, // visitTypeInsn
  396. 0, //INSTANCEOF, // -
  397. -1, //MONITORENTER, // visitInsn
  398. -1, //MONITOREXIT, // -
  399. NA, //WIDE, // NOT VISITED
  400. NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
  401. -1, //IFNULL, // visitJumpInsn
  402. -1, //IFNONNULL, // -
  403. NA, //GOTO_W, // -
  404. NA, //JSR_W, // -
  405. };
  406. for (i = 0; i < b.length; ++i) {
  407. System.err.print((char)('E' + b[i]));
  408. }
  409. System.err.println();
  410. */
  411. }
  412. // --------------------------------------------------------------------------
  413. // Constructor
  414. // --------------------------------------------------------------------------
  415. /**
  416. * Constructs a CodeWriter.
  417. *
  418. * @param cw the class writer in which the method must be added.
  419. * @param computeMaxs <tt>true</tt> if the maximum stack size and number of
  420. * local variables must be automatically computed.
  421. */
  422. protected CodeWriter (final ClassWriter cw, final boolean computeMaxs) {
  423. if (cw.firstMethod == null) {
  424. cw.firstMethod = this;
  425. cw.lastMethod = this;
  426. } else {
  427. cw.lastMethod.next = this;
  428. cw.lastMethod = this;
  429. }
  430. this.cw = cw;
  431. this.computeMaxs = computeMaxs;
  432. if (computeMaxs) {
  433. // pushes the first block onto the stack of blocks to be visited
  434. currentBlock = new Label();
  435. currentBlock.pushed = true;
  436. blockStack = currentBlock;
  437. }
  438. }
  439. /**
  440. * Initializes this CodeWriter to define the bytecode of the specified method.
  441. *
  442. * @param access the method's access flags (see {@link Constants}).
  443. * @param name the method's name.
  444. * @param desc the method's descriptor (see {@link Type Type}).
  445. * @param exceptions the internal names of the method's exceptions. May be
  446. * <tt>null</tt>.
  447. */
  448. protected void init (
  449. final int access,
  450. final String name,
  451. final String desc,
  452. final String[] exceptions)
  453. {
  454. this.access = access;
  455. this.name = cw.newUTF8(name);
  456. this.desc = cw.newUTF8(desc);
  457. if (exceptions != null && exceptions.length > 0) {
  458. exceptionCount = exceptions.length;
  459. this.exceptions = new int[exceptionCount];
  460. for (int i = 0; i < exceptionCount; ++i) {
  461. this.exceptions[i] = cw.newClass(exceptions[i]).index;
  462. }
  463. }
  464. if (computeMaxs) {
  465. // updates maxLocals
  466. int size = getArgumentsAndReturnSizes(desc) >> 2;
  467. if ((access & Constants.ACC_STATIC) != 0) {
  468. --size;
  469. }
  470. if (size > maxLocals) {
  471. maxLocals = size;
  472. }
  473. }
  474. }
  475. // --------------------------------------------------------------------------
  476. // Implementation of the CodeVisitor interface
  477. // --------------------------------------------------------------------------
  478. public void visitInsn (final int opcode) {
  479. if (computeMaxs) {
  480. // updates current and max stack sizes
  481. int size = stackSize + SIZE[opcode];
  482. if (size > maxStackSize) {
  483. maxStackSize = size;
  484. }
  485. stackSize = size;
  486. // if opcode == ATHROW or xRETURN, ends current block (no successor)
  487. if ((opcode >= Constants.IRETURN && opcode <= Constants.RETURN) ||
  488. opcode == Constants.ATHROW)
  489. {
  490. if (currentBlock != null) {
  491. currentBlock.maxStackSize = maxStackSize;
  492. currentBlock = null;
  493. }
  494. }
  495. }
  496. // adds the instruction to the bytecode of the method
  497. code.put1(opcode);
  498. }
  499. public void visitIntInsn (final int opcode, final int operand) {
  500. if (computeMaxs && opcode != Constants.NEWARRAY) {
  501. // updates current and max stack sizes only if opcode == NEWARRAY
  502. // (stack size variation = 0 for BIPUSH or SIPUSH)
  503. int size = stackSize + 1;
  504. if (size > maxStackSize) {
  505. maxStackSize = size;
  506. }
  507. stackSize = size;
  508. }
  509. // adds the instruction to the bytecode of the method
  510. if (opcode == Constants.SIPUSH) {
  511. code.put12(opcode, operand);
  512. } else { // BIPUSH or NEWARRAY
  513. code.put11(opcode, operand);
  514. }
  515. }
  516. public void visitVarInsn (final int opcode, final int var) {
  517. if (computeMaxs) {
  518. // updates current and max stack sizes
  519. if (opcode == Constants.RET) {
  520. // no stack change, but end of current block (no successor)
  521. if (currentBlock != null) {
  522. currentBlock.maxStackSize = maxStackSize;
  523. currentBlock = null;
  524. }
  525. } else { // xLOAD or xSTORE
  526. int size = stackSize + SIZE[opcode];
  527. if (size > maxStackSize) {
  528. maxStackSize = size;
  529. }
  530. stackSize = size;
  531. }
  532. // updates max locals
  533. int n;
  534. if (opcode == Constants.LLOAD || opcode == Constants.DLOAD ||
  535. opcode == Constants.LSTORE || opcode == Constants.DSTORE)
  536. {
  537. n = var + 2;
  538. } else {
  539. n = var + 1;
  540. }
  541. if (n > maxLocals) {
  542. maxLocals = n;
  543. }
  544. }
  545. // adds the instruction to the bytecode of the method
  546. if (var < 4 && opcode != Constants.RET) {
  547. int opt;
  548. if (opcode < Constants.ISTORE) {
  549. opt = 26 /*ILOAD_0*/ + ((opcode - Constants.ILOAD) << 2) + var;
  550. } else {
  551. opt = 59 /*ISTORE_0*/ + ((opcode - Constants.ISTORE) << 2) + var;
  552. }
  553. code.put1(opt);
  554. } else if (var >= 256) {
  555. code.put1(196 /*WIDE*/).put12(opcode, var);
  556. } else {
  557. code.put11(opcode, var);
  558. }
  559. }
  560. public void visitTypeInsn (final int opcode, final String desc) {
  561. if (computeMaxs && opcode == Constants.NEW) {
  562. // updates current and max stack sizes only if opcode == NEW
  563. // (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF)
  564. int size = stackSize + 1;
  565. if (size > maxStackSize) {
  566. maxStackSize = size;
  567. }
  568. stackSize = size;
  569. }
  570. // adds the instruction to the bytecode of the method
  571. code.put12(opcode, cw.newClass(desc).index);
  572. }
  573. public void visitFieldInsn (
  574. final int opcode,
  575. final String owner,
  576. final String name,
  577. final String desc)
  578. {
  579. if (computeMaxs) {
  580. int size;
  581. // computes the stack size variation
  582. char c = desc.charAt(0);
  583. switch (opcode) {
  584. case Constants.GETSTATIC:
  585. size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
  586. break;
  587. case Constants.PUTSTATIC:
  588. size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
  589. break;
  590. case Constants.GETFIELD:
  591. size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
  592. break;
  593. //case Constants.PUTFIELD:
  594. default:
  595. size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
  596. break;
  597. }
  598. // updates current and max stack sizes
  599. if (size > maxStackSize) {
  600. maxStackSize = size;
  601. }
  602. stackSize = size;
  603. }
  604. // adds the instruction to the bytecode of the method
  605. code.put12(opcode, cw.newField(owner, name, desc).index);
  606. }
  607. public void visitMethodInsn (
  608. final int opcode,
  609. final String owner,
  610. final String name,
  611. final String desc)
  612. {
  613. Item i;
  614. if (opcode == Constants.INVOKEINTERFACE) {
  615. i = cw.newItfMethod(owner, name, desc);
  616. } else {
  617. i = cw.newMethod(owner, name, desc);
  618. }
  619. int argSize = i.intVal;
  620. if (computeMaxs) {
  621. // computes the stack size variation. In order not to recompute several
  622. // times this variation for the same Item, we use the intVal field of
  623. // this item to store this variation, once it has been computed. More
  624. // precisely this intVal field stores the sizes of the arguments and of
  625. // the return value corresponding to desc.
  626. if (argSize == 0) {
  627. // the above sizes have not been computed yet, so we compute them...
  628. argSize = getArgumentsAndReturnSizes(desc);
  629. // ... and we save them in order not to recompute them in the future
  630. i.intVal = argSize;
  631. }
  632. int size;
  633. if (opcode == Constants.INVOKESTATIC) {
  634. size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
  635. } else {
  636. size = stackSize - (argSize >> 2) + (argSize & 0x03);
  637. }
  638. // updates current and max stack sizes
  639. if (size > maxStackSize) {
  640. maxStackSize = size;
  641. }
  642. stackSize = size;
  643. }
  644. // adds the instruction to the bytecode of the method
  645. if (opcode == Constants.INVOKEINTERFACE) {
  646. if (!computeMaxs) {
  647. if (argSize == 0) {
  648. argSize = getArgumentsAndReturnSizes(desc);
  649. i.intVal = argSize;
  650. }
  651. }
  652. code.put12(Constants.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
  653. } else {
  654. code.put12(opcode, i.index);
  655. }
  656. }
  657. public void visitJumpInsn (final int opcode, final Label label) {
  658. if (CHECK) {
  659. if (label.owner == null) {
  660. label.owner = this;
  661. } else if (label.owner != this) {
  662. throw new IllegalArgumentException();
  663. }
  664. }
  665. if (computeMaxs) {
  666. if (opcode == Constants.GOTO) {
  667. // no stack change, but end of current block (with one new successor)
  668. if (currentBlock != null) {
  669. currentBlock.maxStackSize = maxStackSize;
  670. addSuccessor(stackSize, label);
  671. currentBlock = null;
  672. }
  673. } else if (opcode == Constants.JSR) {
  674. if (currentBlock != null) {
  675. addSuccessor(stackSize + 1, label);
  676. }
  677. } else {
  678. // updates current stack size (max stack size unchanged because stack
  679. // size variation always negative in this case)
  680. stackSize += SIZE[opcode];
  681. if (currentBlock != null) {
  682. addSuccessor(stackSize, label);
  683. }
  684. }
  685. }
  686. // adds the instruction to the bytecode of the method
  687. if (label.resolved && label.position - code.length < Short.MIN_VALUE) {
  688. // case of a backward jump with an offset < -32768. In this case we
  689. // automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx <l>
  690. // with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the "opposite" opcode
  691. // of IFxxx (i.e., IFNE for IFEQ) and where <l'> designates the
  692. // instruction just after the GOTO_W.
  693. if (opcode == Constants.GOTO) {
  694. code.put1(200); // GOTO_W
  695. } else if (opcode == Constants.JSR) {
  696. code.put1(201); // JSR_W
  697. } else {
  698. code.put1(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1);
  699. code.put2(8); // jump offset
  700. code.put1(200); // GOTO_W
  701. }
  702. label.put(this, code, code.length - 1, true);
  703. } else {
  704. // case of a backward jump with an offset >= -32768, or of a forward jump
  705. // with, of course, an unknown offset. In these cases we store the offset
  706. // in 2 bytes (which will be increased in resizeInstructions, if needed).
  707. code.put1(opcode);
  708. label.put(this, code, code.length - 1, false);
  709. }
  710. }
  711. public void visitLabel (final Label label) {
  712. if (CHECK) {
  713. if (label.owner == null) {
  714. label.owner = this;
  715. } else if (label.owner != this) {
  716. throw new IllegalArgumentException();
  717. }
  718. }
  719. if (computeMaxs) {
  720. if (currentBlock != null) {
  721. // ends current block (with one new successor)
  722. currentBlock.maxStackSize = maxStackSize;
  723. addSuccessor(stackSize, label);
  724. }
  725. // begins a new current block,
  726. // resets the relative current and max stack sizes
  727. currentBlock = label;
  728. stackSize = 0;
  729. maxStackSize = 0;
  730. }
  731. // resolves previous forward references to label, if any
  732. resize |= label.resolve(this, code.length, code.data);
  733. }
  734. public void visitLdcInsn (final Object cst) {
  735. Item i = cw.newCst(cst);
  736. if (computeMaxs) {
  737. int size;
  738. // computes the stack size variation
  739. if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
  740. size = stackSize + 2;
  741. } else {
  742. size = stackSize + 1;
  743. }
  744. // updates current and max stack sizes
  745. if (size > maxStackSize) {
  746. maxStackSize = size;
  747. }
  748. stackSize = size;
  749. }
  750. // adds the instruction to the bytecode of the method
  751. int index = i.index;
  752. if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
  753. code.put12(20 /*LDC2_W*/, index);
  754. } else if (index >= 256) {
  755. code.put12(19 /*LDC_W*/, index);
  756. } else {
  757. code.put11(Constants.LDC, index);
  758. }
  759. }
  760. public void visitIincInsn (final int var, final int increment) {
  761. if (computeMaxs) {
  762. // updates max locals only (no stack change)
  763. int n = var + 1;
  764. if (n > maxLocals) {
  765. maxLocals = n;
  766. }
  767. }
  768. // adds the instruction to the bytecode of the method
  769. if ((var > 255) || (increment > 127) || (increment < -128)) {
  770. code.put1(196 /*WIDE*/).put12(Constants.IINC, var).put2(increment);
  771. } else {
  772. code.put1(Constants.IINC).put11(var, increment);
  773. }
  774. }
  775. public void visitTableSwitchInsn (
  776. final int min,
  777. final int max,
  778. final Label dflt,
  779. final Label labels[])
  780. {
  781. if (computeMaxs) {
  782. // updates current stack size (max stack size unchanged)
  783. --stackSize;
  784. // ends current block (with many new successors)
  785. if (currentBlock != null) {
  786. currentBlock.maxStackSize = maxStackSize;
  787. addSuccessor(stackSize, dflt);
  788. for (int i = 0; i < labels.length; ++i) {
  789. addSuccessor(stackSize, labels[i]);
  790. }
  791. currentBlock = null;
  792. }
  793. }
  794. // adds the instruction to the bytecode of the method
  795. int source = code.length;
  796. code.put1(Constants.TABLESWITCH);
  797. while (code.length % 4 != 0) {
  798. code.put1(0);
  799. }
  800. dflt.put(this, code, source, true);
  801. code.put4(min).put4(max);
  802. for (int i = 0; i < labels.length; ++i) {
  803. labels[i].put(this, code, source, true);
  804. }
  805. }
  806. public void visitLookupSwitchInsn (
  807. final Label dflt,
  808. final int keys[],
  809. final Label labels[])
  810. {
  811. if (computeMaxs) {
  812. // updates current stack size (max stack size unchanged)
  813. --stackSize;
  814. // ends current block (with many new successors)
  815. if (currentBlock != null) {
  816. currentBlock.maxStackSize = maxStackSize;
  817. addSuccessor(stackSize, dflt);
  818. for (int i = 0; i < labels.length; ++i) {
  819. addSuccessor(stackSize, labels[i]);
  820. }
  821. currentBlock = null;
  822. }
  823. }
  824. // adds the instruction to the bytecode of the method
  825. int source = code.length;
  826. code.put1(Constants.LOOKUPSWITCH);
  827. while (code.length % 4 != 0) {
  828. code.put1(0);
  829. }
  830. dflt.put(this, code, source, true);
  831. code.put4(labels.length);
  832. for (int i = 0; i < labels.length; ++i) {
  833. code.put4(keys[i]);
  834. labels[i].put(this, code, source, true);
  835. }
  836. }
  837. public void visitMultiANewArrayInsn (final String desc, final int dims) {
  838. if (computeMaxs) {
  839. // updates current stack size (max stack size unchanged because stack
  840. // size variation always negative or null)
  841. stackSize += 1 - dims;
  842. }
  843. // adds the instruction to the bytecode of the method
  844. Item classItem = cw.newClass(desc);
  845. code.put12(Constants.MULTIANEWARRAY, classItem.index).put1(dims);
  846. }
  847. public void visitTryCatchBlock (
  848. final Label start,
  849. final Label end,
  850. final Label handler,
  851. final String type)
  852. {
  853. if (CHECK) {
  854. if (start.owner != this || end.owner != this || handler.owner != this) {
  855. throw new IllegalArgumentException();
  856. }
  857. if (!start.resolved || !end.resolved || !handler.resolved) {
  858. throw new IllegalArgumentException();
  859. }
  860. }
  861. if (computeMaxs) {
  862. // pushes handler block onto the stack of blocks to be visited
  863. if (!handler.pushed) {
  864. handler.beginStackSize = 1;
  865. handler.pushed = true;
  866. handler.next = blockStack;
  867. blockStack = handler;
  868. }
  869. }
  870. ++catchCount;
  871. if (catchTable == null) {
  872. catchTable = new ByteVector();
  873. }
  874. catchTable.put2(start.position);
  875. catchTable.put2(end.position);
  876. catchTable.put2(handler.position);
  877. catchTable.put2(type != null ? cw.newClass(type).index : 0);
  878. }
  879. public void visitMaxs (final int maxStack, final int maxLocals) {
  880. if (computeMaxs) {
  881. // true (non relative) max stack size
  882. int max = 0;
  883. // control flow analysis algorithm: while the block stack is not empty,
  884. // pop a block from this stack, update the max stack size, compute
  885. // the true (non relative) begin stack size of the successors of this
  886. // block, and push these successors onto the stack (unless they have
  887. // already been pushed onto the stack). Note: by hypothesis, the {@link
  888. // Label#beginStackSize} of the blocks in the block stack are the true
  889. // (non relative) beginning stack sizes of these blocks.
  890. Label stack = blockStack;
  891. while (stack != null) {
  892. // pops a block from the stack
  893. Label l = stack;
  894. stack = stack.next;
  895. // computes the true (non relative) max stack size of this block
  896. int start = l.beginStackSize;
  897. int blockMax = start + l.maxStackSize;
  898. // updates the global max stack size
  899. if (blockMax > max) {
  900. max = blockMax;
  901. }
  902. // analyses the successors of the block
  903. Edge b = l.successors;
  904. while (b != null) {
  905. l = b.successor;
  906. // if this successor has not already been pushed onto the stack...
  907. if (!l.pushed) {
  908. // computes the true beginning stack size of this successor block
  909. l.beginStackSize = start + b.stackSize;
  910. // pushes this successor onto the stack
  911. l.pushed = true;
  912. l.next = stack;
  913. stack = l;
  914. }
  915. b = b.next;
  916. }
  917. }
  918. this.maxStack = max;
  919. // releases all the Edge objects used by this CodeWriter
  920. synchronized (SIZE) {
  921. // appends the [head ... tail] list at the beginning of the pool list
  922. if (tail != null) {
  923. tail.poolNext = pool;
  924. pool = head;
  925. }
  926. }
  927. } else {
  928. this.maxStack = maxStack;
  929. this.maxLocals = maxLocals;
  930. }
  931. }
  932. public void visitLocalVariable (
  933. final String name,
  934. final String desc,
  935. final Label start,
  936. final Label end,
  937. final int index)
  938. {
  939. if (CHECK) {
  940. if (start.owner != this || !start.resolved) {
  941. throw new IllegalArgumentException();
  942. }
  943. if (end.owner != this || !end.resolved) {
  944. throw new IllegalArgumentException();
  945. }
  946. }
  947. if (localVar == null) {
  948. cw.newUTF8("LocalVariableTable");
  949. localVar = new ByteVector();
  950. }
  951. ++localVarCount;
  952. localVar.put2(start.position);
  953. localVar.put2(end.position - start.position);
  954. localVar.put2(cw.newUTF8(name).index);
  955. localVar.put2(cw.newUTF8(desc).index);
  956. localVar.put2(index);
  957. }
  958. public void visitLineNumber (final int line, final Label start) {
  959. if (CHECK) {
  960. if (start.owner != this || !start.resolved) {
  961. throw new IllegalArgumentException();
  962. }
  963. }
  964. if (lineNumber == null) {
  965. cw.newUTF8("LineNumberTable");
  966. lineNumber = new ByteVector();
  967. }
  968. ++lineNumberCount;
  969. lineNumber.put2(start.position);
  970. lineNumber.put2(line);
  971. }
  972. // --------------------------------------------------------------------------
  973. // Utility methods: control flow analysis algorithm
  974. // --------------------------------------------------------------------------
  975. /**
  976. * Computes the size of the arguments and of the return value of a method.
  977. *
  978. * @param desc the descriptor of a method.
  979. * @return the size of the arguments of the method (plus one for the implicit
  980. * this argument), argSize, and the size of its return value, retSize,
  981. * packed into a single int i = <tt>(argSize << 2) | retSize</tt>
  982. * (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
  983. * <tt>i & 0x03</tt>).
  984. */
  985. private static int getArgumentsAndReturnSizes (final String desc) {
  986. int n = 1;
  987. int c = 1;
  988. while (true) {
  989. char car = desc.charAt(c++);
  990. if (car == ')') {
  991. car = desc.charAt(c);
  992. return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
  993. } else if (car == 'L') {
  994. while (desc.charAt(c++) != ';') {
  995. }
  996. n += 1;
  997. } else if (car == '[') {
  998. while ((car = desc.charAt(c)) == '[') {
  999. ++c;
  1000. }
  1001. if (car == 'D' || car == 'J') {
  1002. n -= 1;
  1003. }
  1004. } else if (car == 'D' || car == 'J') {
  1005. n += 2;
  1006. } else {
  1007. n += 1;
  1008. }
  1009. }
  1010. }
  1011. /**
  1012. * Adds a successor to the {@link #currentBlock currentBlock} block.
  1013. *
  1014. * @param stackSize the current (relative) stack size in the current block.
  1015. * @param successor the successor block to be added to the current block.
  1016. */
  1017. private void addSuccessor (final int stackSize, final Label successor) {
  1018. Edge b;
  1019. // creates a new Edge object or reuses one from the shared pool
  1020. synchronized (SIZE) {
  1021. if (pool == null) {
  1022. b = new Edge();
  1023. } else {
  1024. b = pool;
  1025. // removes b from the pool
  1026. pool = pool.poolNext;
  1027. }
  1028. }
  1029. // adds the previous Edge to the list of Edges used by this CodeWriter
  1030. if (tail == null) {
  1031. tail = b;
  1032. }
  1033. b.poolNext = head;
  1034. head = b;
  1035. // initializes the previous Edge object...
  1036. b.stackSize = stackSize;
  1037. b.successor = successor;
  1038. // ...and adds it to the successor list of the currentBlock block
  1039. b.next = currentBlock.successors;
  1040. currentBlock.successors = b;
  1041. }
  1042. // --------------------------------------------------------------------------
  1043. // Utility methods: dump bytecode array
  1044. // --------------------------------------------------------------------------
  1045. /**
  1046. * Returns the size of the bytecode of this method.
  1047. *
  1048. * @return the size of the bytecode of this method.
  1049. */
  1050. final int getSize () {
  1051. if (resize) {
  1052. // replaces the temporary jump opcodes introduced by Label.resolve.
  1053. resizeInstructions(new int[0], new int[0], 0);
  1054. }
  1055. int size = 8;
  1056. if (code.length > 0) {
  1057. cw.newUTF8("Code");
  1058. size += 18 + code.length + 8 * catchCount;
  1059. if (localVar != null) {
  1060. size += 8 + localVar.length;
  1061. }
  1062. if (lineNumber != null) {
  1063. size += 8 + lineNumber.length;
  1064. }
  1065. }
  1066. if (exceptionCount > 0) {
  1067. cw.newUTF8("Exceptions");
  1068. size += 8 + 2 * exceptionCount;
  1069. }
  1070. if ((access & Constants.ACC_SYNTHETIC) != 0) {
  1071. cw.newUTF8("Synthetic");
  1072. size += 6;
  1073. }
  1074. if ((access & Constants.ACC_DEPRECATED) != 0) {
  1075. cw.newUTF8("Deprecated");
  1076. size += 6;
  1077. }
  1078. return size;
  1079. }
  1080. /**
  1081. * Puts the bytecode of this method in the given byte vector.
  1082. *
  1083. * @param out the byte vector into which the bytecode of this method must be
  1084. * copied.
  1085. */
  1086. final void put (final ByteVector out) {
  1087. out.put2(access).put2(name.index).put2(desc.index);
  1088. int attributeCount = 0;
  1089. if (code.length > 0) {
  1090. ++attributeCount;
  1091. }
  1092. if (exceptionCount > 0) {
  1093. ++attributeCount;
  1094. }
  1095. if ((access & Constants.ACC_SYNTHETIC) != 0) {
  1096. ++attributeCount;
  1097. }
  1098. if ((access & Constants.ACC_DEPRECATED) != 0) {
  1099. ++attributeCount;
  1100. }
  1101. out.put2(attributeCount);
  1102. if (code.length > 0) {
  1103. int size = 12 + code.length + 8 * catchCount;
  1104. if (localVar != null) {
  1105. size += 8 + localVar.length;
  1106. }
  1107. if (lineNumber != null) {
  1108. size += 8 + lineNumber.length;
  1109. }
  1110. out.put2(cw.newUTF8("Code").index).put4(size);
  1111. out.put2(maxStack).put2(maxLocals);
  1112. out.put4(code.length).putByteArray(code.data, 0, code.length);
  1113. out.put2(catchCount);
  1114. if (catchCount > 0) {
  1115. out.putByteArray(catchTable.data, 0, catchTable.length);
  1116. }
  1117. attributeCount = 0;
  1118. if (localVar != null) {
  1119. ++attributeCount;
  1120. }
  1121. if (lineNumber != null) {
  1122. ++attributeCount;
  1123. }
  1124. out.put2(attributeCount);
  1125. if (localVar != null) {
  1126. out.put2(cw.newUTF8("LocalVariableTable").index);
  1127. out.put4(localVar.length + 2).put2(localVarCount);
  1128. out.putByteArray(localVar.data, 0, localVar.length);
  1129. }
  1130. if (lineNumber != null) {
  1131. out.put2(cw.newUTF8("LineNumberTable").index);
  1132. out.put4(lineNumber.length + 2).put2(lineNumberCount);
  1133. out.putByteArray(lineNumber.data, 0, lineNumber.length);
  1134. }
  1135. }
  1136. if (exceptionCount > 0) {
  1137. out.put2(cw.newUTF8("Exceptions").index).put4(2 * exceptionCount + 2);
  1138. out.put2(exceptionCount);
  1139. for (int i = 0; i < exceptionCount; ++i) {
  1140. out.put2(exceptions[i]);
  1141. }
  1142. }
  1143. if ((access & Constants.ACC_SYNTHETIC) != 0) {
  1144. out.put2(cw.newUTF8("Synthetic").index).put4(0);
  1145. }
  1146. if ((access & Constants.ACC_DEPRECATED) != 0) {
  1147. out.put2(cw.newUTF8("Deprecated").index).put4(0);
  1148. }
  1149. }
  1150. // --------------------------------------------------------------------------
  1151. // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
  1152. // --------------------------------------------------------------------------
  1153. /**
  1154. * Resizes the designated instructions, while keeping jump offsets and
  1155. * instruction addresses consistent. This may require to resize other existing
  1156. * instructions, or even to introduce new instructions: for example,
  1157. * increasing the size of an instruction by 2 at the middle of a method can
  1158. * increases the offset of an IFEQ instruction from 32766 to 32768, in which
  1159. * case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W 32765. This, in turn,
  1160. * may require to increase the size of another jump instruction, and so on...
  1161. * All these operations are handled automatically by this method.
  1162. * <p>
  1163. * <i>This method must be called after all the method that is being built has
  1164. * been visited</i>. In particular, the {@link Label Label} objects used to
  1165. * construct the method are no longer valid after this method has been called.
  1166. *
  1167. * @param indexes current positions of the instructions to be resized. Each
  1168. * instruction must be designated by the index of its <i>last</i> byte,
  1169. * plus one (or, in other words, by the index of the <i>first</i> byte of
  1170. * the <i>next</i> instruction).
  1171. * @param sizes the number of bytes to be <i>added</i> to the above
  1172. * instructions. More precisely, for each i &lt; <tt>len</tt>,
  1173. * <tt>sizes</tt>[i] bytes will be added at the end of the instruction
  1174. * designated by <tt>indexes</tt>[i] or, if <tt>sizes</tt>[i] is
  1175. * negative, the <i>last</i> |<tt>sizes[i]</tt>| bytes of the instruction
  1176. * will be removed (the instruction size <i>must not</i> become negative
  1177. * or null). The gaps introduced by this method must be filled in
  1178. * "manually" in the array returned by the {@link #getCode getCode}
  1179. * method.
  1180. * @param len the number of instruction to be resized. Must be smaller than or
  1181. * equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length.
  1182. * @return the <tt>indexes</tt> array, which now contains the new positions of
  1183. * the resized instructions (designated as above).
  1184. */
  1185. protected int[] resizeInstructions (
  1186. final int[] indexes,
  1187. final int[] sizes,
  1188. final int len)
  1189. {
  1190. byte[] b = code.data; // bytecode of the method
  1191. int u, v, label; // indexes in b
  1192. int i, j; // loop indexes
  1193. // 1st step:
  1194. // As explained above, resizing an instruction may require to resize another
  1195. // one, which may require to resize yet another one, and so on. The first
  1196. // step of the algorithm consists in finding all the instructions that
  1197. // need to be resized, without modifying the code. This is done by the
  1198. // following "fix point" algorithm:
  1199. // - parse the code to find the jump instructions whose offset will need
  1200. // more than 2 bytes to be stored (the future offset is computed from the
  1201. // current offset and from the number of bytes that will be inserted or
  1202. // removed between the source and target instructions). For each such
  1203. // instruction, adds an entry in (a copy of) the indexes and sizes arrays
  1204. // (if this has not already been done in a previous iteration!)
  1205. // - if at least one entry has been added during the previous step, go back
  1206. // to the beginning, otherwise stop.
  1207. // In fact the real algorithm is complicated by the fact that the size of
  1208. // TABLESWITCH and LOOKUPSWITCH instructions depends on their position in
  1209. // the bytecode (because of padding). In order to ensure the convergence of
  1210. // the algorithm, the number of bytes to be added or removed from these
  1211. // instructions is over estimated during the previous loop, and computed
  1212. // exactly only after the loop is finished (this requires another pass to
  1213. // parse the bytecode of the method).
  1214. int[] allIndexes = new int[len]; // copy of indexes
  1215. int[] allSizes = new int[len]; // copy of sizes
  1216. boolean[] resize; // instructions to be resized
  1217. int newOffset; // future offset of a jump instruction
  1218. System.arraycopy(indexes, 0, allIndexes, 0, len);
  1219. System.arraycopy(sizes, 0, allSizes, 0, len);
  1220. resize = new boolean[code.length];
  1221. int state = 3; // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
  1222. do {
  1223. if (state == 3) {
  1224. state = 2;
  1225. }
  1226. u = 0;
  1227. while (u < b.length) {
  1228. int opcode = b[u] & 0xFF; // opcode of current instruction
  1229. int insert = 0; // bytes to be added after this instruction
  1230. switch (ClassWriter.TYPE[opcode]) {
  1231. case ClassWriter.NOARG_INSN:
  1232. case ClassWriter.IMPLVAR_INSN:
  1233. u += 1;
  1234. break;
  1235. case ClassWriter.LABEL_INSN:
  1236. if (opcode > 201) {
  1237. // converts temporary opcodes 202 to 217 (inclusive), 218 and 219
  1238. // to IFEQ ... JSR (inclusive), IFNULL and IFNONNULL
  1239. opcode = opcode < 218 ? opcode - 49 : opcode - 20;
  1240. label = u + readUnsignedShort(b, u + 1);
  1241. } else {
  1242. label = u + readShort(b, u + 1);
  1243. }
  1244. newOffset = getNewOffset(allIndexes, allSizes, u, label);
  1245. if (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) {
  1246. if (!resize[u]) {
  1247. if (opcode == Constants.GOTO || opcode == Constants.JSR) {
  1248. // two additional bytes will be required to replace this
  1249. // GOTO or JSR instruction with a GOTO_W or a JSR_W
  1250. insert = 2;
  1251. } else {
  1252. // five additional bytes will be required to replace this
  1253. // IFxxx <l> instruction with IFNOTxxx <l'> GOTO_W <l>, where
  1254. // IFNOTxxx is the "opposite" opcode of IFxxx (i.e., IFNE for
  1255. // IFEQ) and where <l'> designates the instruction just after
  1256. // the GOTO_W.
  1257. insert = 5;
  1258. }
  1259. resize[u] = true;
  1260. }
  1261. }
  1262. u += 3;
  1263. break;
  1264. case ClassWriter.LABELW_INSN:
  1265. u += 5;
  1266. break;
  1267. case ClassWriter.TABL_INSN:
  1268. if (state == 1) {
  1269. // true number of bytes to be added (or removed) from this
  1270. // instruction = (future number of padding bytes - current number
  1271. // of padding byte) - previously over estimated variation =
  1272. // = ((3 - newOffset%4) - (3 - u%4)) - u%4
  1273. // = (-newOffset%4 + u%4) - u%4
  1274. // = -(newOffset & 3)
  1275. newOffset = getNewOffset(allIndexes, allSizes, 0, u);
  1276. insert = -(newOffset & 3);
  1277. } else if (!resize[u]) {
  1278. // over estimation of the number of bytes to be added to this
  1279. // instruction = 3 - current number of padding bytes = 3 - (3 -
  1280. // u%4) = u%4 = u & 3
  1281. insert = u & 3;
  1282. resize[u] = true;
  1283. }
  1284. // skips instruction
  1285. u = u + 4 - (u & 3);
  1286. u += 4*(readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
  1287. break;
  1288. case ClassWriter.LOOK_INSN:
  1289. if (state == 1) {
  1290. // like TABL_INSN
  1291. newOffset = getNewOffset(allIndexes, allSizes, 0, u);
  1292. insert = -(newOffset & 3);
  1293. } else if (!resize[u]) {
  1294. // like TABL_INSN
  1295. insert = u & 3;
  1296. resize[u] = true;
  1297. }
  1298. // skips instruction
  1299. u = u + 4 - (u & 3);
  1300. u += 8*readInt(b, u + 4) + 8;
  1301. break;
  1302. case ClassWriter.WIDE_INSN:
  1303. opcode = b[u + 1] & 0xFF;
  1304. if (opcode == Constants.IINC) {
  1305. u += 6;
  1306. } else {
  1307. u += 4;
  1308. }
  1309. break;
  1310. case ClassWriter.VAR_INSN:
  1311. case ClassWriter.SBYTE_INSN:
  1312. case ClassWriter.LDC_INSN:
  1313. u += 2;
  1314. break;
  1315. case ClassWriter.SHORT_INSN:
  1316. case ClassWriter.LDCW_INSN:
  1317. case ClassWriter.FIELDORMETH_INSN:
  1318. case ClassWriter.TYPE_INSN:
  1319. case ClassWriter.IINC_INSN:
  1320. u += 3;
  1321. break;
  1322. case ClassWriter.ITFMETH_INSN:
  1323. u += 5;
  1324. break;
  1325. // case ClassWriter.MANA_INSN:
  1326. default:
  1327. u += 4;
  1328. break;
  1329. }
  1330. if (insert != 0) {
  1331. // adds a new (u, insert) entry in the allIndexes and allSizes arrays
  1332. int[] newIndexes = new int[allIndexes.length + 1];
  1333. int[] newSizes = new int[allSizes.length + 1];
  1334. System.arraycopy(allIndexes, 0, newIndexes, 0, allIndexes.length);
  1335. System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
  1336. newIndexes[allIndexes.length] = u;
  1337. newSizes[allSizes.length] = insert;
  1338. allIndexes = newIndexes;
  1339. allSizes = newSizes;
  1340. if (insert > 0) {
  1341. state = 3;
  1342. }
  1343. }
  1344. }
  1345. if (state < 3) {
  1346. --state;
  1347. }
  1348. } while (state != 0);
  1349. // 2nd step:
  1350. // copies the bytecode of the method into a new bytevector, updates the
  1351. // offsets, and inserts (or removes) bytes as requested.
  1352. ByteVector newCode = new ByteVector(code.length);
  1353. u = 0;
  1354. while (u < code.length) {
  1355. for (i = allIndexes.length - 1; i >= 0; --i) {
  1356. if (allIndexes[i] == u) {
  1357. if (i < len) {
  1358. if (sizes[i] > 0) {
  1359. newCode.putByteArray(null, 0, sizes[i]);
  1360. } else {
  1361. newCode.length += sizes[i];
  1362. }
  1363. indexes[i] = newCode.length;
  1364. }
  1365. }
  1366. }
  1367. int opcode = b[u] & 0xFF;
  1368. switch (ClassWriter.TYPE[opcode]) {
  1369. case ClassWriter.NOARG_INSN:
  1370. case ClassWriter.IMPLVAR_INSN:
  1371. newCode.put1(opcode);
  1372. u += 1;
  1373. break;
  1374. case ClassWriter.LABEL_INSN:
  1375. if (opcode > 201) {
  1376. // changes temporary opcodes 202 to 217 (inclusive), 218 and 219
  1377. // to IFEQ ..…

Large files files are truncated, but you can click here to view the full file