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.

CodeAttribute.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  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.io.DataInputStream;
  18. import java.io.DataOutputStream;
  19. import java.io.IOException;
  20. import java.util.List;
  21. import java.util.ArrayList;
  22. import java.util.Iterator;
  23. import java.util.Map;
  24. /**
  25. * <code>Code_attribute</code>.
  26. *
  27. * <p>To browse the <code>code</code> field of
  28. * a <code>Code_attribute</code> structure,
  29. * use <code>CodeIterator</code>.
  30. *
  31. * @see CodeIterator
  32. * @see #iterator()
  33. */
  34. public class CodeAttribute extends AttributeInfo implements Opcode {
  35. /**
  36. * The name of this attribute <code>"Code"</code>.
  37. */
  38. public static final String tag = "Code";
  39. // code[] is stored in AttributeInfo.info.
  40. private int maxStack;
  41. private int maxLocals;
  42. private ExceptionTable exceptions;
  43. private ArrayList attributes;
  44. /**
  45. * Constructs a <code>Code_attribute</code>.
  46. *
  47. * @param cp constant pool table
  48. * @param stack <code>max_stack</code>
  49. * @param locals <code>max_locals</code>
  50. * @param code <code>code[]</code>
  51. * @param etable <code>exception_table[]</code>
  52. */
  53. public CodeAttribute(ConstPool cp, int stack, int locals, byte[] code,
  54. ExceptionTable etable)
  55. {
  56. super(cp, tag);
  57. maxStack = stack;
  58. maxLocals = locals;
  59. info = code;
  60. exceptions = etable;
  61. attributes = new ArrayList();
  62. }
  63. /**
  64. * Constructs a copy of <code>Code_attribute</code>.
  65. * Specified class names are replaced during the copy.
  66. *
  67. * @param cp constant pool table.
  68. * @param src source Code attribute.
  69. * @param classnames pairs of replaced and substituted
  70. * class names.
  71. */
  72. private CodeAttribute(ConstPool cp, CodeAttribute src, Map classnames)
  73. throws BadBytecode
  74. {
  75. super(cp, tag);
  76. maxStack = src.getMaxStack();
  77. maxLocals = src.getMaxLocals();
  78. exceptions = src.getExceptionTable().copy(cp, classnames);
  79. attributes = new ArrayList();
  80. List src_attr = src.getAttributes();
  81. int num = src_attr.size();
  82. for (int i = 0; i < num; ++i) {
  83. AttributeInfo ai = (AttributeInfo)src_attr.get(i);
  84. attributes.add(ai.copy(cp, classnames));
  85. }
  86. info = src.copyCode(cp, classnames, exceptions, this);
  87. }
  88. CodeAttribute(ConstPool cp, int name_id, DataInputStream in)
  89. throws IOException
  90. {
  91. super(cp, name_id, (byte[])null);
  92. int attr_len = in.readInt();
  93. maxStack = in.readUnsignedShort();
  94. maxLocals = in.readUnsignedShort();
  95. int code_len = in.readInt();
  96. info = new byte[code_len];
  97. in.readFully(info);
  98. exceptions = new ExceptionTable(cp, in);
  99. attributes = new ArrayList();
  100. int num = in.readUnsignedShort();
  101. for (int i = 0; i < num; ++i)
  102. attributes.add(AttributeInfo.read(cp, in));
  103. }
  104. /**
  105. * Makes a copy. Class names are replaced according to the
  106. * given <code>Map</code> object.
  107. *
  108. * @param newCp the constant pool table used by the new copy.
  109. * @param classnames pairs of replaced and substituted
  110. * class names.
  111. * @exception RuntimeCopyException if a <code>BadBytecode</code>
  112. * exception is thrown, it is
  113. * converted into
  114. * <code>RuntimeCopyException</code>.
  115. *
  116. * @return <code>CodeAttribute</code> object.
  117. */
  118. public AttributeInfo copy(ConstPool newCp, Map classnames)
  119. throws RuntimeCopyException
  120. {
  121. try {
  122. return new CodeAttribute(newCp, this, classnames);
  123. }
  124. catch (BadBytecode e) {
  125. throw new RuntimeCopyException("bad bytecode. fatal?");
  126. }
  127. }
  128. /**
  129. * An exception that may be thrown by <code>copy()</code>
  130. * in <code>CodeAttribute</code>.
  131. */
  132. public static class RuntimeCopyException extends RuntimeException {
  133. /**
  134. * Constructs an exception.
  135. */
  136. public RuntimeCopyException(String s) {
  137. super(s);
  138. }
  139. }
  140. /**
  141. * Returns the length of this <code>attribute_info</code>
  142. * structure.
  143. * The returned value is <code>attribute_length + 6</code>.
  144. */
  145. public int length() {
  146. return 18 + info.length + exceptions.size() * 8
  147. + AttributeInfo.getLength(attributes);
  148. }
  149. void write(DataOutputStream out) throws IOException {
  150. out.writeShort(name); // attribute_name_index
  151. out.writeInt(length() - 6); // attribute_length
  152. out.writeShort(maxStack); // max_stack
  153. out.writeShort(maxLocals); // max_locals
  154. out.writeInt(info.length); // code_length
  155. out.write(info); // code
  156. exceptions.write(out);
  157. out.writeShort(attributes.size()); // attributes_count
  158. AttributeInfo.writeAll(attributes, out); // attributes
  159. }
  160. /**
  161. * This method is not available.
  162. *
  163. * @throws java.lang.UnsupportedOperationException always thrown.
  164. */
  165. public byte[] get() {
  166. throw new UnsupportedOperationException("CodeAttribute.get()");
  167. }
  168. /**
  169. * This method is not available.
  170. *
  171. * @throws java.lang.UnsupportedOperationException always thrown.
  172. */
  173. public void set(byte[] newinfo) {
  174. throw new UnsupportedOperationException("CodeAttribute.set()");
  175. }
  176. void renameClass(String oldname, String newname) {
  177. AttributeInfo.renameClass(attributes, oldname, newname);
  178. }
  179. void renameClass(Map classnames) {
  180. AttributeInfo.renameClass(attributes, classnames);
  181. }
  182. void getRefClasses(Map classnames) {
  183. AttributeInfo.getRefClasses(attributes, classnames);
  184. }
  185. /**
  186. * Returns the name of the class declaring the method including
  187. * this code attribute.
  188. */
  189. public String getDeclaringClass() {
  190. ConstPool cp = getConstPool();
  191. return cp.getClassName();
  192. }
  193. /**
  194. * Returns <code>max_stack</code>.
  195. */
  196. public int getMaxStack() {
  197. return maxStack;
  198. }
  199. /**
  200. * Sets <code>max_stack</code>.
  201. */
  202. public void setMaxStack(int value) {
  203. maxStack = value;
  204. }
  205. /**
  206. * Computes the maximum stack size and sets <code>max_stack</code>
  207. * to the computed size.
  208. *
  209. * @throws BadBytecode if this method fails in computing.
  210. * @return the newly computed value of <code>max_stack</code>
  211. */
  212. public int computeMaxStack() throws BadBytecode {
  213. maxStack = new CodeAnalyzer(this).computeMaxStack();
  214. return maxStack;
  215. }
  216. /**
  217. * Returns <code>max_locals</code>.
  218. */
  219. public int getMaxLocals() {
  220. return maxLocals;
  221. }
  222. /**
  223. * Sets <code>max_locals</code>.
  224. */
  225. public void setMaxLocals(int value) {
  226. maxLocals = value;
  227. }
  228. /**
  229. * Returns <code>code_length</code>.
  230. */
  231. public int getCodeLength() {
  232. return info.length;
  233. }
  234. /**
  235. * Returns <code>code[]</code>.
  236. */
  237. public byte[] getCode() {
  238. return info;
  239. }
  240. /**
  241. * Sets <code>code[]</code>.
  242. */
  243. void setCode(byte[] newinfo) { super.set(newinfo); }
  244. /**
  245. * Makes a new iterator for reading this code attribute.
  246. */
  247. public CodeIterator iterator() {
  248. return new CodeIterator(this);
  249. }
  250. /**
  251. * Returns <code>exception_table[]</code>.
  252. */
  253. public ExceptionTable getExceptionTable() { return exceptions; }
  254. /**
  255. * Returns <code>attributes[]</code>.
  256. * It returns a list of <code>AttributeInfo</code>.
  257. * A new element can be added to the returned list
  258. * and an existing element can be removed from the list.
  259. *
  260. * @see AttributeInfo
  261. */
  262. public List getAttributes() { return attributes; }
  263. /**
  264. * Returns the attribute with the specified name.
  265. * If it is not found, this method returns null.
  266. *
  267. * @param name attribute name
  268. * @return an <code>AttributeInfo</code> object or null.
  269. */
  270. public AttributeInfo getAttribute(String name) {
  271. return AttributeInfo.lookup(attributes, name);
  272. }
  273. /**
  274. * Adds a stack map table. If another copy of stack map table
  275. * is already contained, the old one is removed.
  276. *
  277. * @param smt the stack map table added to this code attribute.
  278. * If it is null, a new stack map is not added.
  279. * Only the old stack map is removed.
  280. */
  281. public void setAttribute(StackMapTable smt) {
  282. AttributeInfo.remove(attributes, StackMapTable.tag);
  283. if (smt != null)
  284. attributes.add(smt);
  285. }
  286. /**
  287. * Adds a stack map table for J2ME (CLDC). If another copy of stack map table
  288. * is already contained, the old one is removed.
  289. *
  290. * @param sm the stack map table added to this code attribute.
  291. * If it is null, a new stack map is not added.
  292. * Only the old stack map is removed.
  293. * @since 3.12
  294. */
  295. public void setAttribute(StackMap sm) {
  296. AttributeInfo.remove(attributes, StackMap.tag);
  297. if (sm != null)
  298. attributes.add(sm);
  299. }
  300. /**
  301. * Copies code.
  302. */
  303. private byte[] copyCode(ConstPool destCp, Map classnames,
  304. ExceptionTable etable, CodeAttribute destCa)
  305. throws BadBytecode
  306. {
  307. int len = getCodeLength();
  308. byte[] newCode = new byte[len];
  309. destCa.info = newCode;
  310. LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(),
  311. newCode, destCp, classnames);
  312. return LdcEntry.doit(newCode, ldc, etable, destCa);
  313. }
  314. private static LdcEntry copyCode(byte[] code, int beginPos, int endPos,
  315. ConstPool srcCp, byte[] newcode,
  316. ConstPool destCp, Map classnameMap)
  317. throws BadBytecode
  318. {
  319. int i2, index;
  320. LdcEntry ldcEntry = null;
  321. for (int i = beginPos; i < endPos; i = i2) {
  322. i2 = CodeIterator.nextOpcode(code, i);
  323. byte c = code[i];
  324. newcode[i] = c;
  325. switch (c & 0xff) {
  326. case LDC_W :
  327. case LDC2_W :
  328. case GETSTATIC :
  329. case PUTSTATIC :
  330. case GETFIELD :
  331. case PUTFIELD :
  332. case INVOKEVIRTUAL :
  333. case INVOKESPECIAL :
  334. case INVOKESTATIC :
  335. case NEW :
  336. case ANEWARRAY :
  337. case CHECKCAST :
  338. case INSTANCEOF :
  339. copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
  340. classnameMap);
  341. break;
  342. case LDC :
  343. index = code[i + 1] & 0xff;
  344. index = srcCp.copy(index, destCp, classnameMap);
  345. if (index < 0x100)
  346. newcode[i + 1] = (byte)index;
  347. else {
  348. newcode[i] = NOP;
  349. newcode[i + 1] = NOP;
  350. LdcEntry ldc = new LdcEntry();
  351. ldc.where = i;
  352. ldc.index = index;
  353. ldc.next = ldcEntry;
  354. ldcEntry = ldc;
  355. }
  356. break;
  357. case INVOKEINTERFACE :
  358. copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
  359. classnameMap);
  360. newcode[i + 3] = code[i + 3];
  361. newcode[i + 4] = code[i + 4];
  362. break;
  363. case INVOKEDYNAMIC :
  364. copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
  365. classnameMap);
  366. newcode[i + 3] = 0;
  367. newcode[i + 4] = 0;
  368. break;
  369. case MULTIANEWARRAY :
  370. copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp,
  371. classnameMap);
  372. newcode[i + 3] = code[i + 3];
  373. break;
  374. default :
  375. while (++i < i2)
  376. newcode[i] = code[i];
  377. break;
  378. }
  379. }
  380. return ldcEntry;
  381. }
  382. private static void copyConstPoolInfo(int i, byte[] code, ConstPool srcCp,
  383. byte[] newcode, ConstPool destCp,
  384. Map classnameMap) {
  385. int index = ((code[i] & 0xff) << 8) | (code[i + 1] & 0xff);
  386. index = srcCp.copy(index, destCp, classnameMap);
  387. newcode[i] = (byte)(index >> 8);
  388. newcode[i + 1] = (byte)index;
  389. }
  390. static class LdcEntry {
  391. LdcEntry next;
  392. int where;
  393. int index;
  394. static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable,
  395. CodeAttribute ca)
  396. throws BadBytecode
  397. {
  398. if (ldc != null)
  399. code = CodeIterator.changeLdcToLdcW(code, etable, ca, ldc);
  400. /* The original code was the following:
  401. while (ldc != null) {
  402. int where = ldc.where;
  403. code = CodeIterator.insertGapCore0(code, where, 1, false, etable, ca);
  404. code[where] = (byte)Opcode.LDC_W;
  405. ByteArray.write16bit(ldc.index, code, where + 1);
  406. ldc = ldc.next;
  407. }
  408. But this code does not support a large method > 32KB.
  409. */
  410. return code;
  411. }
  412. }
  413. /**
  414. * Changes the index numbers of the local variables
  415. * to append a new parameter.
  416. * This method does not update <code>LocalVariableAttribute</code>,
  417. * <code>LocalVariableTypeAttribute</code>,
  418. * <code>StackMapTable</code>, or <code>StackMap</code>.
  419. * These attributes must be explicitly updated.
  420. *
  421. * @param where the index of the new parameter.
  422. * @param size the type size of the new parameter (1 or 2).
  423. *
  424. * @see LocalVariableAttribute#shiftIndex(int, int)
  425. * @see LocalVariableTypeAttribute#shiftIndex(int, int)
  426. * @see StackMapTable#insertLocal(int, int, int)
  427. * @see StackMap#insertLocal(int, int, int)
  428. */
  429. public void insertLocalVar(int where, int size) throws BadBytecode {
  430. CodeIterator ci = iterator();
  431. while (ci.hasNext())
  432. shiftIndex(ci, where, size);
  433. setMaxLocals(getMaxLocals() + size);
  434. }
  435. /**
  436. * @param lessThan If the index of the local variable is
  437. * less than this value, it does not change.
  438. * Otherwise, the index is increased.
  439. * @param delta the indexes of the local variables are
  440. * increased by this value.
  441. */
  442. private static void shiftIndex(CodeIterator ci, int lessThan, int delta) throws BadBytecode {
  443. int index = ci.next();
  444. int opcode = ci.byteAt(index);
  445. if (opcode < ILOAD)
  446. return;
  447. else if (opcode < IASTORE) {
  448. if (opcode < ILOAD_0) {
  449. // iload, lload, fload, dload, aload
  450. shiftIndex8(ci, index, opcode, lessThan, delta);
  451. }
  452. else if (opcode < IALOAD) {
  453. // iload_0, ..., aload_3
  454. shiftIndex0(ci, index, opcode, lessThan, delta, ILOAD_0, ILOAD);
  455. }
  456. else if (opcode < ISTORE)
  457. return;
  458. else if (opcode < ISTORE_0) {
  459. // istore, lstore, ...
  460. shiftIndex8(ci, index, opcode, lessThan, delta);
  461. }
  462. else {
  463. // istore_0, ..., astore_3
  464. shiftIndex0(ci, index, opcode, lessThan, delta, ISTORE_0, ISTORE);
  465. }
  466. }
  467. else if (opcode == IINC) {
  468. int var = ci.byteAt(index + 1);
  469. if (var < lessThan)
  470. return;
  471. var += delta;
  472. if (var < 0x100)
  473. ci.writeByte(var, index + 1);
  474. else {
  475. int plus = (byte)ci.byteAt(index + 2);
  476. int pos = ci.insertExGap(3);
  477. ci.writeByte(WIDE, pos - 3);
  478. ci.writeByte(IINC, pos - 2);
  479. ci.write16bit(var, pos - 1);
  480. ci.write16bit(plus, pos + 1);
  481. }
  482. }
  483. else if (opcode == RET)
  484. shiftIndex8(ci, index, opcode, lessThan, delta);
  485. else if (opcode == WIDE) {
  486. int var = ci.u16bitAt(index + 2);
  487. if (var < lessThan)
  488. return;
  489. var += delta;
  490. ci.write16bit(var, index + 2);
  491. }
  492. }
  493. private static void shiftIndex8(CodeIterator ci, int index, int opcode,
  494. int lessThan, int delta)
  495. throws BadBytecode
  496. {
  497. int var = ci.byteAt(index + 1);
  498. if (var < lessThan)
  499. return;
  500. var += delta;
  501. if (var < 0x100)
  502. ci.writeByte(var, index + 1);
  503. else {
  504. int pos = ci.insertExGap(2);
  505. ci.writeByte(WIDE, pos - 2);
  506. ci.writeByte(opcode, pos - 1);
  507. ci.write16bit(var, pos);
  508. }
  509. }
  510. private static void shiftIndex0(CodeIterator ci, int index, int opcode,
  511. int lessThan, int delta,
  512. int opcode_i_0, int opcode_i)
  513. throws BadBytecode
  514. {
  515. int var = (opcode - opcode_i_0) % 4;
  516. if (var < lessThan)
  517. return;
  518. var += delta;
  519. if (var < 4)
  520. ci.writeByte(opcode + delta, index);
  521. else {
  522. opcode = (opcode - opcode_i_0) / 4 + opcode_i;
  523. if (var < 0x100) {
  524. int pos = ci.insertExGap(1);
  525. ci.writeByte(opcode, pos - 1);
  526. ci.writeByte(var, pos);
  527. }
  528. else {
  529. int pos = ci.insertExGap(3);
  530. ci.writeByte(WIDE, pos - 1);
  531. ci.writeByte(opcode, pos);
  532. ci.write16bit(var, pos + 1);
  533. }
  534. }
  535. }
  536. }