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.

CodeIterator.java 54KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599
  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;
  17. import java.util.ArrayList;
  18. /**
  19. * An iterator for editing a code attribute.
  20. *
  21. * <p>To directly read or edit a bytecode sequence, call {@link #byteAt(int)}, {@link #s16bitAt(int)},
  22. * {@link #writeByte(int, int)}, {@link #write16bit(int, int)}, and other methods.
  23. * For example, if <code>method</code> refers to a <code>CtMethod</code> object,
  24. * the following code substitutes the <code>NOP</code> instruction for the first
  25. * instruction of the method:
  26. *
  27. * <pre>
  28. * CodeAttribute ca = method.getMethodInfo().getCodeAttribute();
  29. * CodeIterator ci = ca.iterator();
  30. * ci.writeByte(Opcode.NOP, 0);</pre>
  31. *
  32. * <p>To visit every instruction, call {@link #next()} on a <code>CodeIterator</code>.
  33. * It returns the index of the first byte of the next instruction.
  34. *
  35. * <p>If there are multiple <code>CodeIterator</code>s referring to the
  36. * same <code>Code_attribute</code>, then inserting a gap by one
  37. * <code>CodeIterator</code> will break the other
  38. * <code>CodeIterator</code>.
  39. *
  40. * <p>This iterator does not provide <code>remove()</code>.
  41. * If a piece of code in a <code>Code_attribute</code> is unnecessary,
  42. * it should be overwritten with <code>NOP</code>.
  43. *
  44. * @see CodeAttribute#iterator()
  45. */
  46. public class CodeIterator implements Opcode {
  47. protected CodeAttribute codeAttr;
  48. protected byte[] bytecode;
  49. protected int endPos;
  50. protected int currentPos;
  51. protected int mark;
  52. protected CodeIterator(CodeAttribute ca) {
  53. codeAttr = ca;
  54. bytecode = ca.getCode();
  55. begin();
  56. }
  57. /**
  58. * Moves to the first instruction.
  59. */
  60. public void begin() {
  61. currentPos = mark = 0;
  62. endPos = getCodeLength();
  63. }
  64. /**
  65. * Moves to the given index.
  66. *
  67. * <p>The index of the next instruction is set to the given index.
  68. * The successive call to <code>next()</code>
  69. * returns the index that has been given to <code>move()</code>.
  70. *
  71. * <p>Note that the index is into the byte array returned by
  72. * <code>get().getCode()</code>.
  73. *
  74. * @see CodeAttribute#getCode()
  75. */
  76. public void move(int index) {
  77. currentPos = index;
  78. }
  79. /**
  80. * Sets a mark to the bytecode at the given index.
  81. * The mark can be used to track the position of that bytecode
  82. * when code blocks are inserted.
  83. * If a code block is inclusively inserted at the position of the
  84. * bytecode, the mark is set to the inserted code block.
  85. *
  86. * @see #getMark()
  87. * @since 3.11
  88. */
  89. public void setMark(int index) {
  90. mark = index;
  91. }
  92. /**
  93. * Gets the index of the position of the mark set by
  94. * <code>setMark</code>.
  95. *
  96. * @return the index of the position.
  97. * @see #setMark(int)
  98. * @since 3.11
  99. */
  100. public int getMark() { return mark; }
  101. /**
  102. * Returns a Code attribute read with this iterator.
  103. */
  104. public CodeAttribute get() {
  105. return codeAttr;
  106. }
  107. /**
  108. * Returns <code>code_length</code> of <code>Code_attribute</code>.
  109. */
  110. public int getCodeLength() {
  111. return bytecode.length;
  112. }
  113. /**
  114. * Returns the unsigned 8bit value at the given index.
  115. */
  116. public int byteAt(int index) { return bytecode[index] & 0xff; }
  117. /**
  118. * Writes an 8bit value at the given index.
  119. */
  120. public void writeByte(int value, int index) {
  121. bytecode[index] = (byte)value;
  122. }
  123. /**
  124. * Returns the unsigned 16bit value at the given index.
  125. */
  126. public int u16bitAt(int index) {
  127. return ByteArray.readU16bit(bytecode, index);
  128. }
  129. /**
  130. * Returns the signed 16bit value at the given index.
  131. */
  132. public int s16bitAt(int index) {
  133. return ByteArray.readS16bit(bytecode, index);
  134. }
  135. /**
  136. * Writes a 16 bit integer at the index.
  137. */
  138. public void write16bit(int value, int index) {
  139. ByteArray.write16bit(value, bytecode, index);
  140. }
  141. /**
  142. * Returns the signed 32bit value at the given index.
  143. */
  144. public int s32bitAt(int index) {
  145. return ByteArray.read32bit(bytecode, index);
  146. }
  147. /**
  148. * Writes a 32bit integer at the index.
  149. */
  150. public void write32bit(int value, int index) {
  151. ByteArray.write32bit(value, bytecode, index);
  152. }
  153. /**
  154. * Writes a byte array at the index.
  155. *
  156. * @param code may be a zero-length array.
  157. */
  158. public void write(byte[] code, int index) {
  159. int len = code.length;
  160. for (int j = 0; j < len; ++j)
  161. bytecode[index++] = code[j];
  162. }
  163. /**
  164. * Returns true if there is more instructions.
  165. */
  166. public boolean hasNext() { return currentPos < endPos; }
  167. /**
  168. * Returns the index of the next instruction
  169. * (not the operand following the current opcode).
  170. *
  171. * <p>Note that the index is into the byte array returned by
  172. * <code>get().getCode()</code>.
  173. *
  174. * @see CodeAttribute#getCode()
  175. * @see CodeIterator#byteAt(int)
  176. */
  177. public int next() throws BadBytecode {
  178. int pos = currentPos;
  179. currentPos = nextOpcode(bytecode, pos);
  180. return pos;
  181. }
  182. /**
  183. * Obtains the value that the next call
  184. * to <code>next()</code> will return.
  185. *
  186. * <p>This method is side-effects free.
  187. * Successive calls to <code>lookAhead()</code> return the
  188. * same value until <code>next()</code> is called.
  189. */
  190. public int lookAhead() {
  191. return currentPos;
  192. }
  193. /**
  194. * Moves to the instruction for
  195. * either <code>super()</code> or <code>this()</code>.
  196. *
  197. * <p>This method skips all the instructions for computing arguments
  198. * to <code>super()</code> or <code>this()</code>, which should be
  199. * placed at the beginning of a constructor body.
  200. *
  201. * <p>This method returns the index of INVOKESPECIAL instruction
  202. * executing <code>super()</code> or <code>this()</code>.
  203. * A successive call to <code>next()</code> returns the
  204. * index of the next instruction following that INVOKESPECIAL.
  205. *
  206. * <p>This method works only for a constructor.
  207. *
  208. * @return the index of the INVOKESPECIAL instruction, or -1
  209. * if a constructor invocation is not found.
  210. */
  211. public int skipConstructor() throws BadBytecode {
  212. return skipSuperConstructor0(-1);
  213. }
  214. /**
  215. * Moves to the instruction for <code>super()</code>.
  216. *
  217. * <p>This method skips all the instructions for computing arguments to
  218. * <code>super()</code>, which should be
  219. * placed at the beginning of a constructor body.
  220. *
  221. * <p>This method returns the index of INVOKESPECIAL instruction
  222. * executing <code>super()</code>.
  223. * A successive call to <code>next()</code> returns the
  224. * index of the next instruction following that INVOKESPECIAL.
  225. *
  226. * <p>This method works only for a constructor.
  227. *
  228. * @return the index of the INVOKESPECIAL instruction, or -1
  229. * if a super constructor invocation is not found
  230. * but <code>this()</code> is found.
  231. */
  232. public int skipSuperConstructor() throws BadBytecode {
  233. return skipSuperConstructor0(0);
  234. }
  235. /**
  236. * Moves to the instruction for <code>this()</code>.
  237. *
  238. * <p>This method skips all the instructions for computing arguments to
  239. * <code>this()</code>, which should be
  240. * placed at the beginning of a constructor body.
  241. *
  242. * <p>This method returns the index of INVOKESPECIAL instruction
  243. * executing <code>this()</code>.
  244. * A successive call to <code>next()</code> returns the
  245. * index of the next instruction following that INVOKESPECIAL.
  246. *
  247. * <p>This method works only for a constructor.
  248. *
  249. * @return the index of the INVOKESPECIAL instruction, or -1
  250. * if a explicit constructor invocation is not found
  251. * but <code>super()</code> is found.
  252. */
  253. public int skipThisConstructor() throws BadBytecode {
  254. return skipSuperConstructor0(1);
  255. }
  256. /* skipSuper 1: this(), 0: super(), -1: both.
  257. */
  258. private int skipSuperConstructor0(int skipThis) throws BadBytecode {
  259. begin();
  260. ConstPool cp = codeAttr.getConstPool();
  261. String thisClassName = codeAttr.getDeclaringClass();
  262. int nested = 0;
  263. while (hasNext()) {
  264. int index = next();
  265. int c = byteAt(index);
  266. if (c == NEW)
  267. ++nested;
  268. else if (c == INVOKESPECIAL) {
  269. int mref = ByteArray.readU16bit(bytecode, index + 1);
  270. if (cp.getMethodrefName(mref).equals(MethodInfo.nameInit))
  271. if (--nested < 0) {
  272. if (skipThis < 0)
  273. return index;
  274. String cname = cp.getMethodrefClassName(mref);
  275. if (cname.equals(thisClassName) == (skipThis > 0))
  276. return index;
  277. else
  278. break;
  279. }
  280. }
  281. }
  282. begin();
  283. return -1;
  284. }
  285. /**
  286. * Inserts the given bytecode sequence
  287. * before the next instruction that would be returned by
  288. * <code>next()</code> (not before the instruction returned
  289. * by the last call to <code>next()</code>).
  290. * Branch offsets and the exception table are also updated.
  291. *
  292. * <p>If the next instruction is at the beginning of a block statement,
  293. * then the bytecode is inserted within that block.
  294. *
  295. * <p>An extra gap may be inserted at the end of the inserted
  296. * bytecode sequence for adjusting alignment if the code attribute
  297. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  298. *
  299. * @param code inserted bytecode sequence.
  300. * @return the index indicating the first byte of the
  301. * inserted byte sequence.
  302. */
  303. public int insert(byte[] code)
  304. throws BadBytecode
  305. {
  306. return insert0(currentPos, code, false);
  307. }
  308. /**
  309. * Inserts the given bytecode sequence
  310. * before the instruction at the given index <code>pos</code>.
  311. * Branch offsets and the exception table are also updated.
  312. *
  313. * <p>If the instruction at the given index is at the beginning
  314. * of a block statement,
  315. * then the bytecode is inserted within that block.
  316. *
  317. * <p>An extra gap may be inserted at the end of the inserted
  318. * bytecode sequence for adjusting alignment if the code attribute
  319. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  320. *
  321. * <p>The index at which the byte sequence is actually inserted
  322. * might be different from pos since some other bytes might be
  323. * inserted at other positions (e.g. to change <code>GOTO</code>
  324. * to <code>GOTO_W</code>).
  325. *
  326. * @param pos the index at which a byte sequence is inserted.
  327. * @param code inserted bytecode sequence.
  328. */
  329. public void insert(int pos, byte[] code) throws BadBytecode {
  330. insert0(pos, code, false);
  331. }
  332. /**
  333. * Inserts the given bytecode sequence
  334. * before the instruction at the given index <code>pos</code>.
  335. * Branch offsets and the exception table are also updated.
  336. *
  337. * <p>If the instruction at the given index is at the beginning
  338. * of a block statement,
  339. * then the bytecode is inserted within that block.
  340. *
  341. * <p>An extra gap may be inserted at the end of the inserted
  342. * bytecode sequence for adjusting alignment if the code attribute
  343. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  344. *
  345. * @param pos the index at which a byte sequence is inserted.
  346. * @param code inserted bytecode sequence.
  347. * @return the index indicating the first byte of the
  348. * inserted byte sequence, which might be
  349. * different from pos.
  350. * @since 3.11
  351. */
  352. public int insertAt(int pos, byte[] code) throws BadBytecode {
  353. return insert0(pos, code, false);
  354. }
  355. /**
  356. * Inserts the given bytecode sequence exclusively
  357. * before the next instruction that would be returned by
  358. * <code>next()</code> (not before the instruction returned
  359. * by tha last call to <code>next()</code>).
  360. * Branch offsets and the exception table are also updated.
  361. *
  362. * <p>If the next instruction is at the beginning of a block statement,
  363. * then the bytecode is excluded from that block.
  364. *
  365. * <p>An extra gap may be inserted at the end of the inserted
  366. * bytecode sequence for adjusting alignment if the code attribute
  367. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  368. *
  369. * @param code inserted bytecode sequence.
  370. * @return the index indicating the first byte of the
  371. * inserted byte sequence.
  372. */
  373. public int insertEx(byte[] code)
  374. throws BadBytecode
  375. {
  376. return insert0(currentPos, code, true);
  377. }
  378. /**
  379. * Inserts the given bytecode sequence exclusively
  380. * before the instruction at the given index <code>pos</code>.
  381. * Branch offsets and the exception table are also updated.
  382. *
  383. * <p>If the instruction at the given index is at the beginning
  384. * of a block statement,
  385. * then the bytecode is excluded from that block.
  386. *
  387. * <p>An extra gap may be inserted at the end of the inserted
  388. * bytecode sequence for adjusting alignment if the code attribute
  389. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  390. *
  391. * <p>The index at which the byte sequence is actually inserted
  392. * might be different from pos since some other bytes might be
  393. * inserted at other positions (e.g. to change <code>GOTO</code>
  394. * to <code>GOTO_W</code>).
  395. *
  396. * @param pos the index at which a byte sequence is inserted.
  397. * @param code inserted bytecode sequence.
  398. */
  399. public void insertEx(int pos, byte[] code) throws BadBytecode {
  400. insert0(pos, code, true);
  401. }
  402. /**
  403. * Inserts the given bytecode sequence exclusively
  404. * before the instruction at the given index <code>pos</code>.
  405. * Branch offsets and the exception table are also updated.
  406. *
  407. * <p>If the instruction at the given index is at the beginning
  408. * of a block statement,
  409. * then the bytecode is excluded from that block.
  410. *
  411. * <p>An extra gap may be inserted at the end of the inserted
  412. * bytecode sequence for adjusting alignment if the code attribute
  413. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  414. *
  415. * @param pos the index at which a byte sequence is inserted.
  416. * @param code inserted bytecode sequence.
  417. * @return the index indicating the first byte of the
  418. * inserted byte sequence, which might be
  419. * different from pos.
  420. * @since 3.11
  421. */
  422. public int insertExAt(int pos, byte[] code) throws BadBytecode {
  423. return insert0(pos, code, true);
  424. }
  425. /**
  426. * @return the index indicating the first byte of the
  427. * inserted byte sequence.
  428. */
  429. private int insert0(int pos, byte[] code, boolean exclusive)
  430. throws BadBytecode
  431. {
  432. int len = code.length;
  433. if (len <= 0)
  434. return pos;
  435. // currentPos will change.
  436. pos = insertGapAt(pos, len, exclusive).position;
  437. int p = pos;
  438. for (int j = 0; j < len; ++j)
  439. bytecode[p++] = code[j];
  440. return pos;
  441. }
  442. /**
  443. * Inserts a gap
  444. * before the next instruction that would be returned by
  445. * <code>next()</code> (not before the instruction returned
  446. * by the last call to <code>next()</code>).
  447. * Branch offsets and the exception table are also updated.
  448. * The inserted gap is filled with NOP. The gap length may be
  449. * extended to a multiple of 4.
  450. *
  451. * <p>If the next instruction is at the beginning of a block statement,
  452. * then the gap is inserted within that block.
  453. *
  454. * @param length gap length
  455. * @return the index indicating the first byte of the inserted gap.
  456. */
  457. public int insertGap(int length) throws BadBytecode {
  458. return insertGapAt(currentPos, length, false).position;
  459. }
  460. /**
  461. * Inserts a gap in front of the instruction at the given
  462. * index <code>pos</code>.
  463. * Branch offsets and the exception table are also updated.
  464. * The inserted gap is filled with NOP. The gap length may be
  465. * extended to a multiple of 4.
  466. *
  467. * <p>If the instruction at the given index is at the beginning
  468. * of a block statement,
  469. * then the gap is inserted within that block.
  470. *
  471. * @param pos the index at which a gap is inserted.
  472. * @param length gap length.
  473. * @return the length of the inserted gap.
  474. * It might be bigger than <code>length</code>.
  475. */
  476. public int insertGap(int pos, int length) throws BadBytecode {
  477. return insertGapAt(pos, length, false).length;
  478. }
  479. /**
  480. * Inserts an exclusive gap
  481. * before the next instruction that would be returned by
  482. * <code>next()</code> (not before the instruction returned
  483. * by the last call to <code>next()</code>).
  484. * Branch offsets and the exception table are also updated.
  485. * The inserted gap is filled with NOP. The gap length may be
  486. * extended to a multiple of 4.
  487. *
  488. * <p>If the next instruction is at the beginning of a block statement,
  489. * then the gap is excluded from that block.
  490. *
  491. * @param length gap length
  492. * @return the index indicating the first byte of the inserted gap.
  493. */
  494. public int insertExGap(int length) throws BadBytecode {
  495. return insertGapAt(currentPos, length, true).position;
  496. }
  497. /**
  498. * Inserts an exclusive gap in front of the instruction at the given
  499. * index <code>pos</code>.
  500. * Branch offsets and the exception table are also updated.
  501. * The inserted gap is filled with NOP. The gap length may be
  502. * extended to a multiple of 4.
  503. *
  504. * <p>If the instruction at the given index is at the beginning
  505. * of a block statement,
  506. * then the gap is excluded from that block.
  507. *
  508. * @param pos the index at which a gap is inserted.
  509. * @param length gap length.
  510. * @return the length of the inserted gap.
  511. * It might be bigger than <code>length</code>.
  512. */
  513. public int insertExGap(int pos, int length) throws BadBytecode {
  514. return insertGapAt(pos, length, true).length;
  515. }
  516. /**
  517. * An inserted gap.
  518. *
  519. * @since 3.11
  520. */
  521. public static class Gap {
  522. /**
  523. * The position of the gap.
  524. */
  525. public int position;
  526. /**
  527. * The length of the gap.
  528. */
  529. public int length;
  530. }
  531. /**
  532. * Inserts an inclusive or exclusive gap in front of the instruction
  533. * at the given index <code>pos</code>.
  534. * Branch offsets and the exception table in the method body
  535. * are also updated. The inserted gap is filled with NOP.
  536. * The gap length may be extended to a multiple of 4.
  537. *
  538. * <p>Suppose that the instruction at the given index is at the
  539. * beginning of a block statement. If the gap is inclusive,
  540. * then it is included within that block. If the gap is exclusive,
  541. * then it is excluded from that block.
  542. *
  543. * <p>The index at which the gap is actually inserted
  544. * might be different from pos since some other bytes might be
  545. * inserted at other positions (e.g. to change <code>GOTO</code>
  546. * to <code>GOTO_W</code>). The index is available from the <code>Gap</code>
  547. * object returned by this method.
  548. *
  549. * <p>Suppose that the gap is inserted at the position of
  550. * the next instruction that would be returned by
  551. * <code>next()</code> (not the last instruction returned
  552. * by the last call to <code>next()</code>). The next
  553. * instruction returned by <code>next()</code> after the gap is
  554. * inserted is still the same instruction. It is not <code>NOP</code>
  555. * at the first byte of the inserted gap.
  556. *
  557. * @param pos the index at which a gap is inserted.
  558. * @param length gap length.
  559. * @param exclusive true if exclusive, otherwise false.
  560. * @return the position and the length of the inserted gap.
  561. * @since 3.11
  562. */
  563. public Gap insertGapAt(int pos, int length, boolean exclusive)
  564. throws BadBytecode
  565. {
  566. /**
  567. * cursorPos indicates the next bytecode whichever exclusive is
  568. * true or false.
  569. */
  570. Gap gap = new Gap();
  571. if (length <= 0) {
  572. gap.position = pos;
  573. gap.length = 0;
  574. return gap;
  575. }
  576. byte[] c;
  577. int length2;
  578. if (bytecode.length + length > Short.MAX_VALUE) {
  579. // currentPos might change after calling insertGapCore0w().
  580. c = insertGapCore0w(bytecode, pos, length, exclusive,
  581. get().getExceptionTable(), codeAttr, gap);
  582. pos = gap.position;
  583. length2 = length; // == gap.length
  584. }
  585. else {
  586. int cur = currentPos;
  587. c = insertGapCore0(bytecode, pos, length, exclusive,
  588. get().getExceptionTable(), codeAttr);
  589. // insertGapCore0() never changes pos.
  590. length2 = c.length - bytecode.length;
  591. gap.position = pos;
  592. gap.length = length2;
  593. if (cur >= pos)
  594. currentPos = cur + length2;
  595. if (mark > pos || (mark == pos && exclusive))
  596. mark += length2;
  597. }
  598. codeAttr.setCode(c);
  599. bytecode = c;
  600. endPos = getCodeLength();
  601. updateCursors(pos, length2);
  602. return gap;
  603. }
  604. /**
  605. * Is called when a gap is inserted. The default implementation is empty.
  606. * A subclass can override this method so that cursors will be updated.
  607. *
  608. * @param pos the position where a gap is inserted.
  609. * @param length the length of the gap.
  610. */
  611. protected void updateCursors(int pos, int length) {
  612. // empty
  613. }
  614. /**
  615. * Copies and inserts the entries in the given exception table
  616. * at the beginning of the exception table in the code attribute
  617. * edited by this object.
  618. *
  619. * @param offset the value added to the code positions included
  620. * in the entries.
  621. */
  622. public void insert(ExceptionTable et, int offset) {
  623. codeAttr.getExceptionTable().add(0, et, offset);
  624. }
  625. /**
  626. * Appends the given bytecode sequence at the end.
  627. *
  628. * @param code the bytecode appended.
  629. * @return the position of the first byte of the appended bytecode.
  630. */
  631. public int append(byte[] code) {
  632. int size = getCodeLength();
  633. int len = code.length;
  634. if (len <= 0)
  635. return size;
  636. appendGap(len);
  637. byte[] dest = bytecode;
  638. for (int i = 0; i < len; ++i)
  639. dest[i + size] = code[i];
  640. return size;
  641. }
  642. /**
  643. * Appends a gap at the end of the bytecode sequence.
  644. *
  645. * @param gapLength gap length
  646. */
  647. public void appendGap(int gapLength) {
  648. byte[] code = bytecode;
  649. int codeLength = code.length;
  650. byte[] newcode = new byte[codeLength + gapLength];
  651. int i;
  652. for (i = 0; i < codeLength; ++i)
  653. newcode[i] = code[i];
  654. for (i = codeLength; i < codeLength + gapLength; ++i)
  655. newcode[i] = NOP;
  656. codeAttr.setCode(newcode);
  657. bytecode = newcode;
  658. endPos = getCodeLength();
  659. }
  660. /**
  661. * Copies and appends the entries in the given exception table
  662. * at the end of the exception table in the code attribute
  663. * edited by this object.
  664. *
  665. * @param offset the value added to the code positions included
  666. * in the entries.
  667. */
  668. public void append(ExceptionTable et, int offset) {
  669. ExceptionTable table = codeAttr.getExceptionTable();
  670. table.add(table.size(), et, offset);
  671. }
  672. /* opcodeLegth is used for implementing nextOpcode().
  673. */
  674. private static final int opcodeLength[] = {
  675. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3,
  676. 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  677. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1,
  678. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  679. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  680. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  681. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1,
  682. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
  683. 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3,
  684. 3, 3, 3, 3, 3, 5, 5, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
  685. 5, 5
  686. };
  687. // 0 .. LOOKUPSWITCH, TABLESWITCH, WIDE
  688. /**
  689. * Calculates the index of the next opcode.
  690. */
  691. static int nextOpcode(byte[] code, int index)
  692. throws BadBytecode
  693. {
  694. int opcode;
  695. try {
  696. opcode = code[index] & 0xff;
  697. }
  698. catch (IndexOutOfBoundsException e) {
  699. throw new BadBytecode("invalid opcode address");
  700. }
  701. try {
  702. int len = opcodeLength[opcode];
  703. if (len > 0)
  704. return index + len;
  705. else if (opcode == WIDE)
  706. if (code[index + 1] == (byte)IINC) // WIDE IINC
  707. return index + 6;
  708. else
  709. return index + 4; // WIDE ...
  710. else {
  711. int index2 = (index & ~3) + 8;
  712. if (opcode == LOOKUPSWITCH) {
  713. int npairs = ByteArray.read32bit(code, index2);
  714. return index2 + npairs * 8 + 4;
  715. }
  716. else if (opcode == TABLESWITCH) {
  717. int low = ByteArray.read32bit(code, index2);
  718. int high = ByteArray.read32bit(code, index2 + 4);
  719. return index2 + (high - low + 1) * 4 + 8;
  720. }
  721. // else
  722. // throw new BadBytecode(opcode);
  723. }
  724. }
  725. catch (IndexOutOfBoundsException e) {
  726. }
  727. // opcode is UNUSED or an IndexOutOfBoundsException was thrown.
  728. throw new BadBytecode(opcode);
  729. }
  730. // methods for implementing insertGap().
  731. static class AlignmentException extends Exception {}
  732. /**
  733. * insertGapCore0() inserts a gap (some NOPs).
  734. * It cannot handle a long code sequence more than 32K. All branch offsets must be
  735. * signed 16bits.
  736. *
  737. * If "where" is the beginning of a block statement and exclusive is false,
  738. * then the inserted gap is also included in the block statement.
  739. * "where" must indicate the first byte of an opcode.
  740. * The inserted gap is filled with NOP. gapLength may be extended to
  741. * a multiple of 4.
  742. *
  743. * This method was also called from CodeAttribute.LdcEntry.doit().
  744. *
  745. * @param where It must indicate the first byte of an opcode.
  746. */
  747. static byte[] insertGapCore0(byte[] code, int where, int gapLength,
  748. boolean exclusive, ExceptionTable etable, CodeAttribute ca)
  749. throws BadBytecode
  750. {
  751. if (gapLength <= 0)
  752. return code;
  753. try {
  754. return insertGapCore1(code, where, gapLength, exclusive, etable, ca);
  755. }
  756. catch (AlignmentException e) {
  757. try {
  758. return insertGapCore1(code, where, (gapLength + 3) & ~3,
  759. exclusive, etable, ca);
  760. }
  761. catch (AlignmentException e2) {
  762. throw new RuntimeException("fatal error?");
  763. }
  764. }
  765. }
  766. private static byte[] insertGapCore1(byte[] code, int where, int gapLength,
  767. boolean exclusive, ExceptionTable etable,
  768. CodeAttribute ca)
  769. throws BadBytecode, AlignmentException
  770. {
  771. int codeLength = code.length;
  772. byte[] newcode = new byte[codeLength + gapLength];
  773. insertGap2(code, where, gapLength, codeLength, newcode, exclusive);
  774. etable.shiftPc(where, gapLength, exclusive);
  775. LineNumberAttribute na
  776. = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
  777. if (na != null)
  778. na.shiftPc(where, gapLength, exclusive);
  779. LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute(
  780. LocalVariableAttribute.tag);
  781. if (va != null)
  782. va.shiftPc(where, gapLength, exclusive);
  783. LocalVariableAttribute vta
  784. = (LocalVariableAttribute)ca.getAttribute(
  785. LocalVariableAttribute.typeTag);
  786. if (vta != null)
  787. vta.shiftPc(where, gapLength, exclusive);
  788. StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag);
  789. if (smt != null)
  790. smt.shiftPc(where, gapLength, exclusive);
  791. StackMap sm = (StackMap)ca.getAttribute(StackMap.tag);
  792. if (sm != null)
  793. sm.shiftPc(where, gapLength, exclusive);
  794. return newcode;
  795. }
  796. private static void insertGap2(byte[] code, int where, int gapLength,
  797. int endPos, byte[] newcode, boolean exclusive)
  798. throws BadBytecode, AlignmentException
  799. {
  800. int nextPos;
  801. int i = 0;
  802. int j = 0;
  803. for (; i < endPos; i = nextPos) {
  804. if (i == where) {
  805. int j2 = j + gapLength;
  806. while (j < j2)
  807. newcode[j++] = NOP;
  808. }
  809. nextPos = nextOpcode(code, i);
  810. int inst = code[i] & 0xff;
  811. // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr
  812. if ((153 <= inst && inst <= 168)
  813. || inst == IFNULL || inst == IFNONNULL) {
  814. /* 2bytes *signed* offset */
  815. int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff);
  816. offset = newOffset(i, offset, where, gapLength, exclusive);
  817. newcode[j] = code[i];
  818. ByteArray.write16bit(offset, newcode, j + 1);
  819. j += 3;
  820. }
  821. else if (inst == GOTO_W || inst == JSR_W) {
  822. /* 4bytes offset */
  823. int offset = ByteArray.read32bit(code, i + 1);
  824. offset = newOffset(i, offset, where, gapLength, exclusive);
  825. newcode[j++] = code[i];
  826. ByteArray.write32bit(offset, newcode, j);
  827. j += 4;
  828. }
  829. else if (inst == TABLESWITCH) {
  830. if (i != j && (gapLength & 3) != 0)
  831. throw new AlignmentException();
  832. int i2 = (i & ~3) + 4; // 0-3 byte padding
  833. // IBM JVM 1.4.2 cannot run the following code:
  834. // int i0 = i;
  835. // while (i0 < i2)
  836. // newcode[j++] = code[i0++];
  837. // So extracting this code into an external method.
  838. // see JIRA JASSIST-74.
  839. j = copyGapBytes(newcode, j, code, i, i2);
  840. int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2),
  841. where, gapLength, exclusive);
  842. ByteArray.write32bit(defaultbyte, newcode, j);
  843. int lowbyte = ByteArray.read32bit(code, i2 + 4);
  844. ByteArray.write32bit(lowbyte, newcode, j + 4);
  845. int highbyte = ByteArray.read32bit(code, i2 + 8);
  846. ByteArray.write32bit(highbyte, newcode, j + 8);
  847. j += 12;
  848. int i0 = i2 + 12;
  849. i2 = i0 + (highbyte - lowbyte + 1) * 4;
  850. while (i0 < i2) {
  851. int offset = newOffset(i, ByteArray.read32bit(code, i0),
  852. where, gapLength, exclusive);
  853. ByteArray.write32bit(offset, newcode, j);
  854. j += 4;
  855. i0 += 4;
  856. }
  857. }
  858. else if (inst == LOOKUPSWITCH) {
  859. if (i != j && (gapLength & 3) != 0)
  860. throw new AlignmentException();
  861. int i2 = (i & ~3) + 4; // 0-3 byte padding
  862. // IBM JVM 1.4.2 cannot run the following code:
  863. // int i0 = i;
  864. // while (i0 < i2)
  865. // newcode[j++] = code[i0++];
  866. // So extracting this code into an external method.
  867. // see JIRA JASSIST-74.
  868. j = copyGapBytes(newcode, j, code, i, i2);
  869. int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2),
  870. where, gapLength, exclusive);
  871. ByteArray.write32bit(defaultbyte, newcode, j);
  872. int npairs = ByteArray.read32bit(code, i2 + 4);
  873. ByteArray.write32bit(npairs, newcode, j + 4);
  874. j += 8;
  875. int i0 = i2 + 8;
  876. i2 = i0 + npairs * 8;
  877. while (i0 < i2) {
  878. ByteArray.copy32bit(code, i0, newcode, j);
  879. int offset = newOffset(i,
  880. ByteArray.read32bit(code, i0 + 4),
  881. where, gapLength, exclusive);
  882. ByteArray.write32bit(offset, newcode, j + 4);
  883. j += 8;
  884. i0 += 8;
  885. }
  886. }
  887. else
  888. while (i < nextPos)
  889. newcode[j++] = code[i++];
  890. }
  891. }
  892. private static int copyGapBytes(byte[] newcode, int j, byte[] code, int i, int iEnd) {
  893. switch (iEnd - i) {
  894. case 4:
  895. newcode[j++] = code[i++];
  896. case 3:
  897. newcode[j++] = code[i++];
  898. case 2:
  899. newcode[j++] = code[i++];
  900. case 1:
  901. newcode[j++] = code[i++];
  902. default:
  903. }
  904. return j;
  905. }
  906. private static int newOffset(int i, int offset, int where,
  907. int gapLength, boolean exclusive) {
  908. int target = i + offset;
  909. if (i < where) {
  910. if (where < target || (exclusive && where == target))
  911. offset += gapLength;
  912. }
  913. else if (i == where) {
  914. // This code is different from the code in Branch#shiftOffset().
  915. // see JASSIST-124.
  916. if (target < where)
  917. offset -= gapLength;
  918. }
  919. else
  920. if (target < where || (!exclusive && where == target))
  921. offset -= gapLength;
  922. return offset;
  923. }
  924. static class Pointers {
  925. int cursor;
  926. int mark0, mark;
  927. ExceptionTable etable;
  928. LineNumberAttribute line;
  929. LocalVariableAttribute vars, types;
  930. StackMapTable stack;
  931. StackMap stack2;
  932. Pointers(int cur, int m, int m0, ExceptionTable et, CodeAttribute ca) {
  933. cursor = cur;
  934. mark = m;
  935. mark0 = m0;
  936. etable = et; // non null
  937. line = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
  938. vars = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.tag);
  939. types = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.typeTag);
  940. stack = (StackMapTable)ca.getAttribute(StackMapTable.tag);
  941. stack2 = (StackMap)ca.getAttribute(StackMap.tag);
  942. }
  943. void shiftPc(int where, int gapLength, boolean exclusive) throws BadBytecode {
  944. if (where < cursor || (where == cursor && exclusive))
  945. cursor += gapLength;
  946. if (where < mark || (where == mark && exclusive))
  947. mark += gapLength;
  948. if (where < mark0 || (where == mark0 && exclusive))
  949. mark0 += gapLength;
  950. etable.shiftPc(where, gapLength, exclusive);
  951. if (line != null)
  952. line.shiftPc(where, gapLength, exclusive);
  953. if (vars != null)
  954. vars.shiftPc(where, gapLength, exclusive);
  955. if (types != null)
  956. types.shiftPc(where, gapLength, exclusive);
  957. if (stack != null)
  958. stack.shiftPc(where, gapLength, exclusive);
  959. if (stack2 != null)
  960. stack2.shiftPc(where, gapLength, exclusive);
  961. }
  962. void shiftForSwitch(int where, int gapLength) throws BadBytecode {
  963. if (stack != null)
  964. stack.shiftForSwitch(where, gapLength);
  965. if (stack2 != null)
  966. stack2.shiftForSwitch(where, gapLength);
  967. }
  968. }
  969. /*
  970. * This method is called from CodeAttribute.LdcEntry.doit().
  971. */
  972. static byte[] changeLdcToLdcW(byte[] code, ExceptionTable etable,
  973. CodeAttribute ca, CodeAttribute.LdcEntry ldcs)
  974. throws BadBytecode
  975. {
  976. Pointers pointers = new Pointers(0, 0, 0, etable, ca);
  977. ArrayList jumps = makeJumpList(code, code.length, pointers);
  978. while (ldcs != null) {
  979. addLdcW(ldcs, jumps);
  980. ldcs = ldcs.next;
  981. }
  982. byte[] r = insertGap2w(code, 0, 0, false, jumps, pointers);
  983. return r;
  984. }
  985. private static void addLdcW(CodeAttribute.LdcEntry ldcs, ArrayList jumps) {
  986. int where = ldcs.where;
  987. LdcW ldcw = new LdcW(where, ldcs.index);
  988. int s = jumps.size();
  989. for (int i = 0; i < s; i++)
  990. if (where < ((Branch)jumps.get(i)).orgPos) {
  991. jumps.add(i, ldcw);
  992. return;
  993. }
  994. jumps.add(ldcw);
  995. }
  996. /*
  997. * insertGapCore0w() can handle a long code sequence more than 32K.
  998. * It guarantees that the length of the inserted gap (NOPs) is equal to
  999. * gapLength. No other NOPs except some NOPs following TABLESWITCH or
  1000. * LOOKUPSWITCH will not be inserted.
  1001. *
  1002. * Note: currentPos might be moved.
  1003. *
  1004. * @param where It must indicate the first byte of an opcode.
  1005. * @param newWhere It contains the updated index of the position where a gap
  1006. * is inserted and the length of the gap.
  1007. * It must not be null.
  1008. */
  1009. private byte[] insertGapCore0w(byte[] code, int where, int gapLength, boolean exclusive,
  1010. ExceptionTable etable, CodeAttribute ca, Gap newWhere)
  1011. throws BadBytecode
  1012. {
  1013. if (gapLength <= 0)
  1014. return code;
  1015. Pointers pointers = new Pointers(currentPos, mark, where, etable, ca);
  1016. ArrayList jumps = makeJumpList(code, code.length, pointers);
  1017. byte[] r = insertGap2w(code, where, gapLength, exclusive, jumps, pointers);
  1018. currentPos = pointers.cursor;
  1019. mark = pointers.mark;
  1020. int where2 = pointers.mark0;
  1021. if (where2 == currentPos && !exclusive)
  1022. currentPos += gapLength;
  1023. if (exclusive)
  1024. where2 -= gapLength;
  1025. newWhere.position = where2;
  1026. newWhere.length = gapLength;
  1027. return r;
  1028. }
  1029. private static byte[] insertGap2w(byte[] code, int where, int gapLength,
  1030. boolean exclusive, ArrayList jumps, Pointers ptrs)
  1031. throws BadBytecode
  1032. {
  1033. int n = jumps.size();
  1034. if (gapLength > 0) {
  1035. ptrs.shiftPc(where, gapLength, exclusive);
  1036. for (int i = 0; i < n; i++)
  1037. ((Branch)jumps.get(i)).shift(where, gapLength, exclusive);
  1038. }
  1039. boolean unstable = true;
  1040. do {
  1041. while (unstable) {
  1042. unstable = false;
  1043. for (int i = 0; i < n; i++) {
  1044. Branch b = (Branch)jumps.get(i);
  1045. if (b.expanded()) {
  1046. unstable = true;
  1047. int p = b.pos;
  1048. int delta = b.deltaSize();
  1049. ptrs.shiftPc(p, delta, false);
  1050. for (int j = 0; j < n; j++)
  1051. ((Branch)jumps.get(j)).shift(p, delta, false);
  1052. }
  1053. }
  1054. }
  1055. for (int i = 0; i < n; i++) {
  1056. Branch b = (Branch)jumps.get(i);
  1057. int diff = b.gapChanged();
  1058. if (diff > 0) {
  1059. unstable = true;
  1060. int p = b.pos;
  1061. ptrs.shiftPc(p, diff, false);
  1062. for (int j = 0; j < n; j++)
  1063. ((Branch)jumps.get(j)).shift(p, diff, false);
  1064. }
  1065. }
  1066. } while (unstable);
  1067. return makeExapndedCode(code, jumps, where, gapLength);
  1068. }
  1069. private static ArrayList makeJumpList(byte[] code, int endPos, Pointers ptrs)
  1070. throws BadBytecode
  1071. {
  1072. ArrayList jumps = new ArrayList();
  1073. int nextPos;
  1074. for (int i = 0; i < endPos; i = nextPos) {
  1075. nextPos = nextOpcode(code, i);
  1076. int inst = code[i] & 0xff;
  1077. // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr
  1078. if ((153 <= inst && inst <= 168)
  1079. || inst == IFNULL || inst == IFNONNULL) {
  1080. /* 2bytes *signed* offset */
  1081. int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff);
  1082. Branch b;
  1083. if (inst == GOTO || inst == JSR)
  1084. b = new Jump16(i, offset);
  1085. else
  1086. b = new If16(i, offset);
  1087. jumps.add(b);
  1088. }
  1089. else if (inst == GOTO_W || inst == JSR_W) {
  1090. /* 4bytes offset */
  1091. int offset = ByteArray.read32bit(code, i + 1);
  1092. jumps.add(new Jump32(i, offset));
  1093. }
  1094. else if (inst == TABLESWITCH) {
  1095. int i2 = (i & ~3) + 4; // 0-3 byte padding
  1096. int defaultbyte = ByteArray.read32bit(code, i2);
  1097. int lowbyte = ByteArray.read32bit(code, i2 + 4);
  1098. int highbyte = ByteArray.read32bit(code, i2 + 8);
  1099. int i0 = i2 + 12;
  1100. int size = highbyte - lowbyte + 1;
  1101. int[] offsets = new int[size];
  1102. for (int j = 0; j < size; j++) {
  1103. offsets[j] = ByteArray.read32bit(code, i0);
  1104. i0 += 4;
  1105. }
  1106. jumps.add(new Table(i, defaultbyte, lowbyte, highbyte, offsets, ptrs));
  1107. }
  1108. else if (inst == LOOKUPSWITCH) {
  1109. int i2 = (i & ~3) + 4; // 0-3 byte padding
  1110. int defaultbyte = ByteArray.read32bit(code, i2);
  1111. int npairs = ByteArray.read32bit(code, i2 + 4);
  1112. int i0 = i2 + 8;
  1113. int[] matches = new int[npairs];
  1114. int[] offsets = new int[npairs];
  1115. for (int j = 0; j < npairs; j++) {
  1116. matches[j] = ByteArray.read32bit(code, i0);
  1117. offsets[j] = ByteArray.read32bit(code, i0 + 4);
  1118. i0 += 8;
  1119. }
  1120. jumps.add(new Lookup(i, defaultbyte, matches, offsets, ptrs));
  1121. }
  1122. }
  1123. return jumps;
  1124. }
  1125. private static byte[] makeExapndedCode(byte[] code, ArrayList jumps,
  1126. int where, int gapLength)
  1127. throws BadBytecode
  1128. {
  1129. int n = jumps.size();
  1130. int size = code.length + gapLength;
  1131. for (int i = 0; i < n; i++) {
  1132. Branch b = (Branch)jumps.get(i);
  1133. size += b.deltaSize();
  1134. }
  1135. byte[] newcode = new byte[size];
  1136. int src = 0, dest = 0, bindex = 0;
  1137. int len = code.length;
  1138. Branch b;
  1139. int bpos;
  1140. if (0 < n) {
  1141. b = (Branch)jumps.get(0);
  1142. bpos = b.orgPos;
  1143. }
  1144. else {
  1145. b = null;
  1146. bpos = len; // src will be never equal to bpos
  1147. }
  1148. while (src < len) {
  1149. if (src == where) {
  1150. int pos2 = dest + gapLength;
  1151. while (dest < pos2)
  1152. newcode[dest++] = NOP;
  1153. }
  1154. if (src != bpos)
  1155. newcode[dest++] = code[src++];
  1156. else {
  1157. int s = b.write(src, code, dest, newcode);
  1158. src += s;
  1159. dest += s + b.deltaSize();
  1160. if (++bindex < n) {
  1161. b = (Branch)jumps.get(bindex);
  1162. bpos = b.orgPos;
  1163. }
  1164. else {
  1165. b = null;
  1166. bpos = len;
  1167. }
  1168. }
  1169. }
  1170. return newcode;
  1171. }
  1172. static abstract class Branch {
  1173. int pos, orgPos;
  1174. Branch(int p) { pos = orgPos = p; }
  1175. void shift(int where, int gapLength, boolean exclusive) {
  1176. if (where < pos || (where == pos && exclusive))
  1177. pos += gapLength;
  1178. }
  1179. static int shiftOffset(int i, int offset, int where,
  1180. int gapLength, boolean exclusive) {
  1181. int target = i + offset;
  1182. if (i < where) {
  1183. if (where < target || (exclusive && where == target))
  1184. offset += gapLength;
  1185. }
  1186. else if (i == where) {
  1187. // This code is different from the code in CodeIterator#newOffset().
  1188. // see JASSIST-124.
  1189. if (target < where && exclusive)
  1190. offset -= gapLength;
  1191. else if (where < target && !exclusive)
  1192. offset += gapLength;
  1193. }
  1194. else
  1195. if (target < where || (!exclusive && where == target))
  1196. offset -= gapLength;
  1197. return offset;
  1198. }
  1199. boolean expanded() { return false; }
  1200. int gapChanged() { return 0; }
  1201. int deltaSize() { return 0; } // newSize - oldSize
  1202. // This returns the original instruction size.
  1203. abstract int write(int srcPos, byte[] code, int destPos, byte[] newcode) throws BadBytecode;
  1204. }
  1205. /* used by changeLdcToLdcW() and CodeAttribute.LdcEntry.
  1206. */
  1207. static class LdcW extends Branch {
  1208. int index;
  1209. boolean state;
  1210. LdcW(int p, int i) {
  1211. super(p);
  1212. index = i;
  1213. state = true;
  1214. }
  1215. boolean expanded() {
  1216. if (state) {
  1217. state = false;
  1218. return true;
  1219. }
  1220. else
  1221. return false;
  1222. }
  1223. int deltaSize() { return 1; }
  1224. int write(int srcPos, byte[] code, int destPos, byte[] newcode) {
  1225. newcode[destPos] = LDC_W;
  1226. ByteArray.write16bit(index, newcode, destPos + 1);
  1227. return 2;
  1228. }
  1229. }
  1230. static abstract class Branch16 extends Branch {
  1231. int offset;
  1232. int state;
  1233. static final int BIT16 = 0;
  1234. static final int EXPAND = 1;
  1235. static final int BIT32 = 2;
  1236. Branch16(int p, int off) {
  1237. super(p);
  1238. offset = off;
  1239. state = BIT16;
  1240. }
  1241. void shift(int where, int gapLength, boolean exclusive) {
  1242. offset = shiftOffset(pos, offset, where, gapLength, exclusive);
  1243. super.shift(where, gapLength, exclusive);
  1244. if (state == BIT16)
  1245. if (offset < Short.MIN_VALUE || Short.MAX_VALUE < offset)
  1246. state = EXPAND;
  1247. }
  1248. boolean expanded() {
  1249. if (state == EXPAND) {
  1250. state = BIT32;
  1251. return true;
  1252. }
  1253. else
  1254. return false;
  1255. }
  1256. abstract int deltaSize();
  1257. abstract void write32(int src, byte[] code, int dest, byte[] newcode);
  1258. int write(int src, byte[] code, int dest, byte[] newcode) {
  1259. if (state == BIT32)
  1260. write32(src, code, dest, newcode);
  1261. else {
  1262. newcode[dest] = code[src];
  1263. ByteArray.write16bit(offset, newcode, dest + 1);
  1264. }
  1265. return 3;
  1266. }
  1267. }
  1268. // GOTO or JSR
  1269. static class Jump16 extends Branch16 {
  1270. Jump16(int p, int off) {
  1271. super(p, off);
  1272. }
  1273. int deltaSize() {
  1274. return state == BIT32 ? 2 : 0;
  1275. }
  1276. void write32(int src, byte[] code, int dest, byte[] newcode) {
  1277. newcode[dest] = (byte)(((code[src] & 0xff) == GOTO) ? GOTO_W : JSR_W);
  1278. ByteArray.write32bit(offset, newcode, dest + 1);
  1279. }
  1280. }
  1281. // if<cond>, if_icmp<cond>, or if_acmp<cond>
  1282. static class If16 extends Branch16 {
  1283. If16(int p, int off) {
  1284. super(p, off);
  1285. }
  1286. int deltaSize() {
  1287. return state == BIT32 ? 5 : 0;
  1288. }
  1289. void write32(int src, byte[] code, int dest, byte[] newcode) {
  1290. newcode[dest] = (byte)opcode(code[src] & 0xff);
  1291. newcode[dest + 1] = 0;
  1292. newcode[dest + 2] = 8; // branch_offset = 8
  1293. newcode[dest + 3] = (byte)GOTO_W;
  1294. ByteArray.write32bit(offset - 3, newcode, dest + 4);
  1295. }
  1296. int opcode(int op) {
  1297. if (op == IFNULL)
  1298. return IFNONNULL;
  1299. else if (op == IFNONNULL)
  1300. return IFNULL;
  1301. else {
  1302. if (((op - IFEQ) & 1) == 0)
  1303. return op + 1;
  1304. else
  1305. return op - 1;
  1306. }
  1307. }
  1308. }
  1309. static class Jump32 extends Branch {
  1310. int offset;
  1311. Jump32(int p, int off) {
  1312. super(p);
  1313. offset = off;
  1314. }
  1315. void shift(int where, int gapLength, boolean exclusive) {
  1316. offset = shiftOffset(pos, offset, where, gapLength, exclusive);
  1317. super.shift(where, gapLength, exclusive);
  1318. }
  1319. int write(int src, byte[] code, int dest, byte[] newcode) {
  1320. newcode[dest] = code[src];
  1321. ByteArray.write32bit(offset, newcode, dest + 1);
  1322. return 5;
  1323. }
  1324. }
  1325. static abstract class Switcher extends Branch {
  1326. int gap, defaultByte;
  1327. int[] offsets;
  1328. Pointers pointers;
  1329. Switcher(int pos, int defaultByte, int[] offsets, Pointers ptrs) {
  1330. super(pos);
  1331. this.gap = 3 - (pos & 3);
  1332. this.defaultByte = defaultByte;
  1333. this.offsets = offsets;
  1334. this.pointers = ptrs;
  1335. }
  1336. void shift(int where, int gapLength, boolean exclusive) {
  1337. int p = pos;
  1338. defaultByte = shiftOffset(p, defaultByte, where, gapLength, exclusive);
  1339. int num = offsets.length;
  1340. for (int i = 0; i < num; i++)
  1341. offsets[i] = shiftOffset(p, offsets[i], where, gapLength, exclusive);
  1342. super.shift(where, gapLength, exclusive);
  1343. }
  1344. int gapChanged() {
  1345. int newGap = 3 - (pos & 3);
  1346. if (newGap > gap) {
  1347. int diff = newGap - gap;
  1348. gap = newGap;
  1349. return diff;
  1350. }
  1351. return 0;
  1352. }
  1353. int deltaSize() {
  1354. return gap - (3 - (orgPos & 3));
  1355. }
  1356. int write(int src, byte[] code, int dest, byte[] newcode) throws BadBytecode {
  1357. int padding = 3 - (pos & 3);
  1358. int nops = gap - padding;
  1359. int bytecodeSize = 5 + (3 - (orgPos & 3)) + tableSize();
  1360. if (nops > 0)
  1361. adjustOffsets(bytecodeSize, nops);
  1362. newcode[dest++] = code[src];
  1363. while (padding-- > 0)
  1364. newcode[dest++] = 0;
  1365. ByteArray.write32bit(defaultByte, newcode, dest);
  1366. int size = write2(dest + 4, newcode);
  1367. dest += size + 4;
  1368. while (nops-- > 0)
  1369. newcode[dest++] = NOP;
  1370. return 5 + (3 - (orgPos & 3)) + size;
  1371. }
  1372. abstract int write2(int dest, byte[] newcode);
  1373. abstract int tableSize();
  1374. /* If the new bytecode size is shorter than the original, some NOPs
  1375. * are appended after this branch instruction (tableswitch or
  1376. * lookupswitch) to fill the gap.
  1377. * This method changes a branch offset to point to the first NOP
  1378. * if the offset originally points to the bytecode next to this
  1379. * branch instruction. Otherwise, the bytecode would contain
  1380. * dead code. It complicates the generation of StackMap and
  1381. * StackMapTable.
  1382. */
  1383. void adjustOffsets(int size, int nops) throws BadBytecode {
  1384. pointers.shiftForSwitch(pos + size, nops);
  1385. if (defaultByte == size)
  1386. defaultByte -= nops;
  1387. for (int i = 0; i < offsets.length; i++)
  1388. if (offsets[i] == size)
  1389. offsets[i] -= nops;
  1390. }
  1391. }
  1392. static class Table extends Switcher {
  1393. int low, high;
  1394. Table(int pos, int defaultByte, int low, int high, int[] offsets, Pointers ptrs) {
  1395. super(pos, defaultByte, offsets, ptrs);
  1396. this.low = low;
  1397. this.high = high;
  1398. }
  1399. int write2(int dest, byte[] newcode) {
  1400. ByteArray.write32bit(low, newcode, dest);
  1401. ByteArray.write32bit(high, newcode, dest + 4);
  1402. int n = offsets.length;
  1403. dest += 8;
  1404. for (int i = 0; i < n; i++) {
  1405. ByteArray.write32bit(offsets[i], newcode, dest);
  1406. dest += 4;
  1407. }
  1408. return 8 + 4 * n;
  1409. }
  1410. int tableSize() { return 8 + 4 * offsets.length; }
  1411. }
  1412. static class Lookup extends Switcher {
  1413. int[] matches;
  1414. Lookup(int pos, int defaultByte, int[] matches, int[] offsets, Pointers ptrs) {
  1415. super(pos, defaultByte, offsets, ptrs);
  1416. this.matches = matches;
  1417. }
  1418. int write2(int dest, byte[] newcode) {
  1419. int n = matches.length;
  1420. ByteArray.write32bit(n, newcode, dest);
  1421. dest += 4;
  1422. for (int i = 0; i < n; i++) {
  1423. ByteArray.write32bit(matches[i], newcode, dest);
  1424. ByteArray.write32bit(offsets[i], newcode, dest + 4);
  1425. dest += 8;
  1426. }
  1427. return 4 + 8 * n;
  1428. }
  1429. int tableSize() { return 4 + 8 * matches.length; }
  1430. }
  1431. }