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

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