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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2003 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. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist.bytecode;
  16. /**
  17. * An iterator for editing a code attribute.
  18. *
  19. * <p>This iterator does not provide <code>remove()</code>.
  20. * If a piece of code in a <code>Code_attribute</code> is unnecessary,
  21. * it should be overwritten with <code>NOP</code>.
  22. *
  23. * @see CodeAttribute#iterator()
  24. */
  25. public class CodeIterator implements Opcode {
  26. protected CodeAttribute codeAttr;
  27. protected byte[] bytecode;
  28. protected int endPos;
  29. protected int currentPos;
  30. CodeIterator(CodeAttribute ca) {
  31. codeAttr = ca;
  32. bytecode = ca.getCode();
  33. begin();
  34. }
  35. /**
  36. * Moves to the first instruction.
  37. */
  38. public void begin() {
  39. currentPos = 0;
  40. endPos = getCodeLength();
  41. }
  42. /**
  43. * Moves to the given index.
  44. *
  45. * <p>The index of the next instruction is set to the given index.
  46. * The successive call to <code>next()</code>
  47. * returns the index that has been given to <code>move()</code>.
  48. *
  49. * <p>Note that the index is into the byte array returned by
  50. * <code>get().getCode()</code>.
  51. *
  52. * @see CodeAttribute#getCode()
  53. */
  54. public void move(int index) {
  55. currentPos = index;
  56. }
  57. /**
  58. * Returns a Code attribute read with this iterator.
  59. */
  60. public CodeAttribute get() {
  61. return codeAttr;
  62. }
  63. /**
  64. * Returns <code>code_length</code> of <code>Code_attribute</code>.
  65. */
  66. public int getCodeLength() {
  67. return bytecode.length;
  68. }
  69. /**
  70. * Returns the unsigned 8bit value at the given index.
  71. */
  72. public int byteAt(int index) { return bytecode[index] & 0xff; }
  73. /**
  74. * Writes an 8bit value at the given index.
  75. */
  76. public void writeByte(int value, int index) {
  77. bytecode[index] = (byte)value;
  78. }
  79. /**
  80. * Returns the unsigned 16bit value at the given index.
  81. */
  82. public int u16bitAt(int index) {
  83. return ByteArray.readU16bit(bytecode, index);
  84. }
  85. /**
  86. * Returns the signed 16bit value at the given index.
  87. */
  88. public int s16bitAt(int index) {
  89. return ByteArray.readS16bit(bytecode, index);
  90. }
  91. /**
  92. * Writes a 16 bit integer at the index.
  93. */
  94. public void write16bit(int value, int index) {
  95. ByteArray.write16bit(value, bytecode, index);
  96. }
  97. /**
  98. * Returns the signed 32bit value at the given index.
  99. */
  100. public int s32bitAt(int index) {
  101. return ByteArray.read32bit(bytecode, index);
  102. }
  103. /**
  104. * Writes a 32bit integer at the index.
  105. */
  106. public void write32bit(int value, int index) {
  107. ByteArray.write32bit(value, bytecode, index);
  108. }
  109. /**
  110. * Writes a byte array at the index.
  111. */
  112. public void write(byte[] code, int index) {
  113. int len = code.length;
  114. for (int j = 0; j < len; ++j)
  115. bytecode[index++] = code[j];
  116. }
  117. /**
  118. * Returns true if there is more instructions.
  119. */
  120. public boolean hasNext() { return currentPos < endPos; }
  121. /**
  122. * Returns the index of the next instruction
  123. * (not the next opcode).
  124. *
  125. * <p>Note that the index is into the byte array returned by
  126. * <code>get().getCode()</code>.
  127. *
  128. * @see CodeAttribute#getCode()
  129. * @see CodeIterator#byteAt(int)
  130. */
  131. public int next() throws BadBytecode {
  132. int pos = currentPos;
  133. currentPos = nextOpcode(bytecode, pos);
  134. return pos;
  135. }
  136. /**
  137. * Moves to the first instruction following
  138. * constructor invocation <code>super()</code> or <code>this()</code>.
  139. *
  140. * <p>This method skips all the instructions for executing
  141. * <code>super()</code> or <code>this()</code>, which should be
  142. * placed at the beginning of a constructor body.
  143. *
  144. * <p>This method returns the index of INVOKESPECIAL instruction
  145. * executing <code>super()</code> or <code>this()</code>.
  146. * A successive call to <code>next()</code> returns the
  147. * index of the next instruction following that INVOKESPECIAL.
  148. *
  149. * <p>This method works only for a constructor.
  150. *
  151. * @return the index of the INVOKESPECIAL instruction, or -1
  152. * if a constructor invocation is not found.
  153. */
  154. public int skipConstructor() throws BadBytecode {
  155. return skipSuperConstructor0(-1);
  156. }
  157. /**
  158. * Moves to the first instruction following super
  159. * constructor invocation <code>super()</code>.
  160. *
  161. * <p>This method skips all the instructions for executing
  162. * <code>super()</code>, which should be
  163. * placed at the beginning of a constructor body.
  164. *
  165. * <p>This method returns the index of INVOKESPECIAL instruction
  166. * executing <code>super()</code>.
  167. * A successive call to <code>next()</code> returns the
  168. * index of the next instruction following that INVOKESPECIAL.
  169. *
  170. * <p>This method works only for a constructor.
  171. *
  172. * @return the index of the INVOKESPECIAL instruction, or -1
  173. * if a super constructor invocation is not found
  174. * but <code>this()</code> is found.
  175. */
  176. public int skipSuperConstructor() throws BadBytecode {
  177. return skipSuperConstructor0(0);
  178. }
  179. /**
  180. * Moves to the first instruction following explicit
  181. * constructor invocation <code>this()</code>.
  182. *
  183. * <p>This method skips all the instructions for executing
  184. * <code>this()</code>, which should be
  185. * placed at the beginning of a constructor body.
  186. *
  187. * <p>This method returns the index of INVOKESPECIAL instruction
  188. * executing <code>this()</code>.
  189. * A successive call to <code>next()</code> returns the
  190. * index of the next instruction following that INVOKESPECIAL.
  191. *
  192. * <p>This method works only for a constructor.
  193. *
  194. * @return the index of the INVOKESPECIAL instruction, or -1
  195. * if a explicit constructor invocation is not found
  196. * but <code>super()</code> is found.
  197. */
  198. public int skipThisConstructor() throws BadBytecode {
  199. return skipSuperConstructor0(1);
  200. }
  201. /* skipSuper 1: this(), 0: super(), -1: both.
  202. */
  203. private int skipSuperConstructor0(int skipThis) throws BadBytecode {
  204. begin();
  205. ConstPool cp = codeAttr.getConstPool();
  206. String thisClassName = codeAttr.getDeclaringClass();
  207. int nested = 0;
  208. while (hasNext()) {
  209. int index = next();
  210. int c = byteAt(index);
  211. if (c == NEW)
  212. ++nested;
  213. else if (c == INVOKESPECIAL) {
  214. int mref = ByteArray.readU16bit(bytecode, index + 1);
  215. if (cp.getMethodrefName(mref).equals(MethodInfo.nameInit))
  216. if (--nested < 0) {
  217. if (skipThis < 0)
  218. return index;
  219. String cname = cp.getMethodrefClassName(mref);
  220. if (cname.equals(thisClassName) == (skipThis > 0))
  221. return index;
  222. else
  223. break;
  224. }
  225. }
  226. }
  227. begin();
  228. return -1;
  229. }
  230. /**
  231. * Inserts the given bytecode sequence
  232. * before the next instruction that would be returned by
  233. * <code>next()</code> (not before the instruction returned
  234. * by tha last call to <code>next()</code>).
  235. * Branch offsets and the exception table are also updated.
  236. *
  237. * <p>If the next instruction is at the beginning of a block statement,
  238. * then the bytecode is inserted within that block.
  239. *
  240. * <p>An extra gap may be inserted at the end of the inserted
  241. * bytecode sequence for adjusting alignment if the code attribute
  242. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  243. *
  244. * @param code inserted bytecode sequence.
  245. * @return the index indicating the first byte of the
  246. * inserted byte sequence.
  247. */
  248. public int insert(byte[] code)
  249. throws BadBytecode
  250. {
  251. int pos = currentPos;
  252. insert0(currentPos, code, false);
  253. return pos;
  254. }
  255. /**
  256. * Inserts the given bytecode sequence
  257. * before the instruction at the given index <code>pos</code>.
  258. * Branch offsets and the exception table are also updated.
  259. *
  260. * <p>If the instruction at the given index is at the beginning
  261. * of a block statement,
  262. * then the bytecode is inserted within that block.
  263. *
  264. * <p>An extra gap may be inserted at the end of the inserted
  265. * bytecode sequence for adjusting alignment if the code attribute
  266. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  267. *
  268. * @param pos the index at which a byte sequence is inserted.
  269. * @param code inserted bytecode sequence.
  270. */
  271. public void insert(int pos, byte[] code) throws BadBytecode {
  272. insert0(pos, code, false);
  273. }
  274. /**
  275. * Inserts the given bytecode sequence exclusively
  276. * before the next instruction that would be returned by
  277. * <code>next()</code> (not before the instruction returned
  278. * by tha last call to <code>next()</code>).
  279. * Branch offsets and the exception table are also updated.
  280. *
  281. * <p>If the next instruction is at the beginning of a block statement,
  282. * then the bytecode is excluded from that block.
  283. *
  284. * <p>An extra gap may be inserted at the end of the inserted
  285. * bytecode sequence for adjusting alignment if the code attribute
  286. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  287. *
  288. * @param code inserted bytecode sequence.
  289. * @return the index indicating the first byte of the
  290. * inserted byte sequence.
  291. */
  292. public int insertEx(byte[] code)
  293. throws BadBytecode
  294. {
  295. int pos = currentPos;
  296. insert0(currentPos, code, true);
  297. return pos;
  298. }
  299. /**
  300. * Inserts the given bytecode sequence exclusively
  301. * before the instruction at the given index <code>pos</code>.
  302. * Branch offsets and the exception table are also updated.
  303. *
  304. * <p>If the instruction at the given index is at the beginning
  305. * of a block statement,
  306. * then the bytecode is excluded from that block.
  307. *
  308. * <p>An extra gap may be inserted at the end of the inserted
  309. * bytecode sequence for adjusting alignment if the code attribute
  310. * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>.
  311. *
  312. * @param pos the index at which a byte sequence is inserted.
  313. * @param code inserted bytecode sequence.
  314. */
  315. public void insertEx(int pos, byte[] code) throws BadBytecode {
  316. insert0(pos, code, true);
  317. }
  318. private void insert0(int pos, byte[] code, boolean exclusive)
  319. throws BadBytecode
  320. {
  321. int len = code.length;
  322. if (len <= 0)
  323. return;
  324. insertGapCore(pos, len, exclusive); // currentPos will change.
  325. for (int j = 0; j < len; ++j)
  326. bytecode[pos++] = code[j];
  327. }
  328. /**
  329. * Inserts a gap
  330. * before the next instruction that would be returned by
  331. * <code>next()</code> (not before the instruction returned
  332. * by tha last call to <code>next()</code>).
  333. * Branch offsets and the exception table are also updated.
  334. * The inserted gap is filled with NOP. The gap length may be
  335. * extended to a multiple of 4.
  336. *
  337. * <p>If the next instruction is at the beginning of a block statement,
  338. * then the gap is inserted within that block.
  339. *
  340. * @param length gap length
  341. * @return the index indicating the first byte of the inserted gap.
  342. */
  343. public int insertGap(int length) throws BadBytecode {
  344. int pos = currentPos;
  345. insertGapCore(currentPos, length, false);
  346. return pos;
  347. }
  348. /**
  349. * Inserts a gap in front of the instruction at the given
  350. * index <code>pos</code>.
  351. * Branch offsets and the exception table are also updated.
  352. * The inserted gap is filled with NOP. The gap length may be
  353. * extended to a multiple of 4.
  354. *
  355. * <p>If the instruction at the given index is at the beginning
  356. * of a block statement,
  357. * then the gap is inserted within that block.
  358. *
  359. * @param pos the index at which a gap is inserted.
  360. * @param length gap length.
  361. * @return the length of the inserted gap.
  362. * It might be bigger than <code>length</code>.
  363. */
  364. public int insertGap(int pos, int length) throws BadBytecode {
  365. return insertGapCore(pos, length, false);
  366. }
  367. /**
  368. * Inserts an exclusive gap
  369. * before the next instruction that would be returned by
  370. * <code>next()</code> (not before the instruction returned
  371. * by tha last call to <code>next()</code>).
  372. * Branch offsets and the exception table are also updated.
  373. * The inserted gap is filled with NOP. The gap length may be
  374. * extended to a multiple of 4.
  375. *
  376. * <p>If the next instruction is at the beginning of a block statement,
  377. * then the gap is excluded from that block.
  378. *
  379. * @param length gap length
  380. * @return the index indicating the first byte of the inserted gap.
  381. */
  382. public int insertExGap(int length) throws BadBytecode {
  383. int pos = currentPos;
  384. insertGapCore(currentPos, length, true);
  385. return pos;
  386. }
  387. /**
  388. * Inserts an exclusive gap in front of the instruction at the given
  389. * index <code>pos</code>.
  390. * Branch offsets and the exception table are also updated.
  391. * The inserted gap is filled with NOP. The gap length may be
  392. * extended to a multiple of 4.
  393. *
  394. * <p>If the instruction at the given index is at the beginning
  395. * of a block statement,
  396. * then the gap is excluded from that block.
  397. *
  398. * @param pos the index at which a gap is inserted.
  399. * @param length gap length.
  400. * @return the length of the inserted gap.
  401. * It might be bigger than <code>length</code>.
  402. */
  403. public int insertExGap(int pos, int length) throws BadBytecode {
  404. return insertGapCore(pos, length, true);
  405. }
  406. /**
  407. * @return the length of the really inserted gap.
  408. */
  409. private int insertGapCore(int pos, int length, boolean exclusive)
  410. throws BadBytecode
  411. {
  412. if (length <= 0)
  413. return 0;
  414. int cur = currentPos;
  415. byte[] c = insertGap(bytecode, pos, length, exclusive,
  416. get().getExceptionTable());
  417. int length2 = c.length - bytecode.length;
  418. if (cur >= pos)
  419. currentPos = cur + length2;
  420. codeAttr.setCode(c);
  421. bytecode = c;
  422. endPos = getCodeLength();
  423. return length2;
  424. }
  425. /**
  426. * Copies and inserts the entries in the given exception table
  427. * at the beginning of the exception table in the code attribute
  428. * edited by this object.
  429. *
  430. * @param offset the value added to the code positions included
  431. * in the entries.
  432. */
  433. public void insert(ExceptionTable et, int offset) {
  434. codeAttr.getExceptionTable().add(0, et, offset);
  435. }
  436. /**
  437. * Appends the given bytecode sequence at the end.
  438. *
  439. * @param code the bytecode appended.
  440. * @return the position of the first byte of the appended bytecode.
  441. */
  442. public int append(byte[] code) {
  443. int size = getCodeLength();
  444. int len = code.length;
  445. if (len <= 0)
  446. return size;
  447. appendGap(len);
  448. byte[] dest = bytecode;
  449. for (int i = 0; i < len; ++i)
  450. dest[i + size] = code[i];
  451. return size;
  452. }
  453. /**
  454. * Appends a gap at the end of the bytecode sequence.
  455. *
  456. * @param length gap length
  457. */
  458. public void appendGap(int gapLength) {
  459. byte[] code = bytecode;
  460. int codeLength = code.length;
  461. byte[] newcode = new byte[codeLength + gapLength];
  462. int i;
  463. for (i = 0; i < codeLength; ++i)
  464. newcode[i] = code[i];
  465. for (i = codeLength; i < codeLength + gapLength; ++i)
  466. newcode[i] = NOP;
  467. codeAttr.setCode(newcode);
  468. bytecode = newcode;
  469. endPos = getCodeLength();
  470. }
  471. /**
  472. * Copies and appends the entries in the given exception table
  473. * at the end of the exception table in the code attribute
  474. * edited by this object.
  475. *
  476. * @param offset the value added to the code positions included
  477. * in the entries.
  478. */
  479. public void append(ExceptionTable et, int offset) {
  480. ExceptionTable table = codeAttr.getExceptionTable();
  481. table.add(table.size(), et, offset);
  482. }
  483. /* opcodeLegth is used for implementing nextOpcode().
  484. */
  485. private static final int opcodeLength[] = {
  486. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3,
  487. 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  488. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1,
  489. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  490. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  491. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  492. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1,
  493. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
  494. 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3,
  495. 3, 3, 3, 3, 3, 5, 0, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3,
  496. 5, 5
  497. };
  498. // 0 .. UNUSED (186), LOOKUPSWITCH, TABLESWITCH, WIDE
  499. /**
  500. * Calculates the index of the next opcode.
  501. */
  502. static int nextOpcode(byte[] code, int index)
  503. throws BadBytecode
  504. {
  505. int opcode;
  506. try {
  507. opcode = code[index] & 0xff;
  508. }
  509. catch (IndexOutOfBoundsException e) {
  510. throw new BadBytecode("invalid opcode address");
  511. }
  512. try {
  513. int len = opcodeLength[opcode];
  514. if (len > 0)
  515. return index + len;
  516. else if (opcode == WIDE)
  517. if (code[index + 1] == (byte)IINC) // WIDE IINC
  518. return index + 6;
  519. else
  520. return index + 4; // WIDE ...
  521. else {
  522. int index2 = (index & ~3) + 8;
  523. if (opcode == LOOKUPSWITCH) {
  524. int npairs = ByteArray.read32bit(code, index2);
  525. return index2 + npairs * 8 + 4;
  526. }
  527. else if (opcode == TABLESWITCH) {
  528. int low = ByteArray.read32bit(code, index2);
  529. int high = ByteArray.read32bit(code, index2 + 4);
  530. return index2 + (high - low + 1) * 4 + 8;
  531. }
  532. // else
  533. // throw new BadBytecode(opcode);
  534. }
  535. }
  536. catch (IndexOutOfBoundsException e) {
  537. }
  538. // opcode is UNUSED or an IndexOutOfBoundsException was thrown.
  539. throw new BadBytecode(opcode);
  540. }
  541. // methods for implementing insertGap().
  542. /* If "where" is the beginning of a block statement, then the inserted
  543. * gap is also included in the block statement.
  544. * "where" must indicate the first byte of an opcode.
  545. * The inserted gap is filled with NOP. gapLength may be extended to
  546. * a multiple of 4.
  547. */
  548. static byte[] insertGap(byte[] code, int where, int gapLength,
  549. boolean exclusive, ExceptionTable etable)
  550. throws BadBytecode
  551. {
  552. if (gapLength <= 0)
  553. return code;
  554. try {
  555. return insertGap0(code, where, gapLength, exclusive, etable);
  556. }
  557. catch (AlignmentException e) {
  558. try {
  559. return insertGap0(code, where, (gapLength + 3) & ~3,
  560. exclusive, etable);
  561. }
  562. catch (AlignmentException e2) {
  563. throw new RuntimeException("fatal error?");
  564. }
  565. }
  566. }
  567. private static byte[] insertGap0(byte[] code, int where, int gapLength,
  568. boolean exclusive, ExceptionTable etable)
  569. throws BadBytecode, AlignmentException
  570. {
  571. int codeLength = code.length;
  572. byte[] newcode = new byte[codeLength + gapLength];
  573. insertGap2(code, where, gapLength, codeLength, newcode, exclusive);
  574. etable.shiftPc(where, gapLength, exclusive);
  575. return newcode;
  576. }
  577. private static void insertGap2(byte[] code, int where, int gapLength,
  578. int endPos, byte[] newcode, boolean exclusive)
  579. throws BadBytecode, AlignmentException
  580. {
  581. int nextPos;
  582. int i = 0;
  583. int j = 0;
  584. for (; i < endPos; i = nextPos) {
  585. if (i == where) {
  586. int j2 = j + gapLength;
  587. while (j < j2)
  588. newcode[j++] = NOP;
  589. }
  590. nextPos = nextOpcode(code, i);
  591. int inst = code[i] & 0xff;
  592. // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr
  593. if ((153 <= inst && inst <= 168)
  594. || inst == IFNULL || inst == IFNONNULL) {
  595. /* 2bytes *signed* offset */
  596. int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff);
  597. offset = newOffset(i, offset, where, gapLength, exclusive);
  598. newcode[j] = code[i];
  599. ByteArray.write16bit(offset, newcode, j + 1);
  600. j += 3;
  601. }
  602. else if (inst == GOTO_W || inst == JSR_W) {
  603. /* 4bytes offset */
  604. int offset = ByteArray.read32bit(code, i + 1);
  605. offset = newOffset(i, offset, where, gapLength, exclusive);
  606. newcode[j++] = code[i];
  607. ByteArray.write32bit(offset, newcode, j);
  608. j += 4;
  609. }
  610. else if (inst == TABLESWITCH) {
  611. if (i != j && (gapLength & 3) != 0)
  612. throw new AlignmentException();
  613. int i0 = i;
  614. int i2 = (i & ~3) + 4; // 0-3 byte padding
  615. while (i0 < i2)
  616. newcode[j++] = code[i0++];
  617. int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2),
  618. where, gapLength, exclusive);
  619. ByteArray.write32bit(defaultbyte, newcode, j);
  620. int lowbyte = ByteArray.read32bit(code, i2 + 4);
  621. ByteArray.write32bit(lowbyte, newcode, j + 4);
  622. int highbyte = ByteArray.read32bit(code, i2 + 8);
  623. ByteArray.write32bit(highbyte, newcode, j + 8);
  624. j += 12;
  625. i0 = i2 + 12;
  626. i2 = i0 + (highbyte - lowbyte + 1) * 4;
  627. while (i0 < i2) {
  628. int offset = newOffset(i, ByteArray.read32bit(code, i0),
  629. where, gapLength, exclusive);
  630. ByteArray.write32bit(offset, newcode, j);
  631. j += 4;
  632. i0 += 4;
  633. }
  634. }
  635. else if (inst == LOOKUPSWITCH) {
  636. if (i != j && (gapLength & 3) != 0)
  637. throw new AlignmentException();
  638. int i0 = i;
  639. int i2 = (i & ~3) + 4; // 0-3 byte padding
  640. while (i0 < i2)
  641. newcode[j++] = code[i0++];
  642. int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2),
  643. where, gapLength, exclusive);
  644. ByteArray.write32bit(defaultbyte, newcode, j);
  645. int npairs = ByteArray.read32bit(code, i2 + 4);
  646. ByteArray.write32bit(npairs, newcode, j + 4);
  647. j += 8;
  648. i0 = i2 + 8;
  649. i2 = i0 + npairs * 8;
  650. while (i0 < i2) {
  651. ByteArray.copy32bit(code, i0, newcode, j);
  652. int offset = newOffset(i,
  653. ByteArray.read32bit(code, i0 + 4),
  654. where, gapLength, exclusive);
  655. ByteArray.write32bit(offset, newcode, j + 4);
  656. j += 8;
  657. i0 += 8;
  658. }
  659. }
  660. else
  661. while (i < nextPos)
  662. newcode[j++] = code[i++];
  663. }
  664. }
  665. private static int newOffset(int i, int offset, int where,
  666. int gapLength, boolean exclusive) {
  667. int target = i + offset;
  668. if (i < where) {
  669. if (where < target || (exclusive && where == target))
  670. offset += gapLength;
  671. }
  672. else
  673. if (target < where || (!exclusive && where == target))
  674. offset -= gapLength;
  675. return offset;
  676. }
  677. }
  678. class AlignmentException extends Exception {
  679. }