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

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