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.

StackMapTable.java 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  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.ByteArrayOutputStream;
  18. import java.io.DataInputStream;
  19. import java.io.DataOutputStream;
  20. import java.io.IOException;
  21. import java.io.PrintWriter;
  22. import java.util.Map;
  23. import javassist.CannotCompileException;
  24. /**
  25. * <code>stack_map</code> attribute.
  26. *
  27. * <p>This is an entry in the attributes table of a Code attribute.
  28. * It was introduced by J2SE 6 for the verification by
  29. * typechecking.
  30. *
  31. * @see StackMap
  32. * @since 3.4
  33. */
  34. public class StackMapTable extends AttributeInfo {
  35. /**
  36. * The name of this attribute <code>"StackMapTable"</code>.
  37. */
  38. public static final String tag = "StackMapTable";
  39. /**
  40. * Constructs a <code>stack_map</code> attribute.
  41. */
  42. StackMapTable(ConstPool cp, byte[] newInfo) {
  43. super(cp, tag, newInfo);
  44. }
  45. StackMapTable(ConstPool cp, int name_id, DataInputStream in)
  46. throws IOException
  47. {
  48. super(cp, name_id, in);
  49. }
  50. /**
  51. * Makes a copy.
  52. *
  53. * @exception RuntimeCopyException if a <code>BadBytecode</code>
  54. * exception is thrown while copying,
  55. * it is converted into
  56. * <code>RuntimeCopyException</code>.
  57. *
  58. */
  59. @Override
  60. public AttributeInfo copy(ConstPool newCp, Map<String,String> classnames)
  61. throws RuntimeCopyException
  62. {
  63. try {
  64. return new StackMapTable(newCp,
  65. new Copier(this.constPool, info, newCp, classnames).doit());
  66. }
  67. catch (BadBytecode e) {
  68. throw new RuntimeCopyException("bad bytecode. fatal?");
  69. }
  70. }
  71. /**
  72. * An exception that may be thrown by <code>copy()</code>
  73. * in <code>StackMapTable</code>.
  74. */
  75. public static class RuntimeCopyException extends RuntimeException {
  76. /** default serialVersionUID */
  77. private static final long serialVersionUID = 1L;
  78. /**
  79. * Constructs an exception.
  80. */
  81. public RuntimeCopyException(String s) {
  82. super(s);
  83. }
  84. }
  85. @Override
  86. void write(DataOutputStream out) throws IOException {
  87. super.write(out);
  88. }
  89. /**
  90. * <code>Top_variable_info.tag</code>.
  91. */
  92. public static final int TOP = 0;
  93. /**
  94. * <code>Integer_variable_info.tag</code>.
  95. */
  96. public static final int INTEGER = 1;
  97. /**
  98. * <code>Float_variable_info.tag</code>.
  99. */
  100. public static final int FLOAT = 2;
  101. /**
  102. * <code>Double_variable_info.tag</code>.
  103. */
  104. public static final int DOUBLE = 3;
  105. /**
  106. * <code>Long_variable_info.tag</code>.
  107. */
  108. public static final int LONG = 4;
  109. /**
  110. * <code>Null_variable_info.tag</code>.
  111. */
  112. public static final int NULL = 5;
  113. /**
  114. * <code>UninitializedThis_variable_info.tag</code>.
  115. */
  116. public static final int THIS = 6;
  117. /**
  118. * <code>Object_variable_info.tag</code>.
  119. */
  120. public static final int OBJECT = 7;
  121. /**
  122. * <code>Uninitialized_variable_info.tag</code>.
  123. */
  124. public static final int UNINIT = 8;
  125. /**
  126. * A code walker for a StackMapTable attribute.
  127. */
  128. public static class Walker {
  129. byte[] info;
  130. int numOfEntries;
  131. /**
  132. * Constructs a walker.
  133. *
  134. * @param smt the StackMapTable that this walker
  135. * walks around.
  136. */
  137. public Walker(StackMapTable smt) {
  138. this(smt.get());
  139. }
  140. /**
  141. * Constructs a walker.
  142. *
  143. * @param data the <code>info</code> field of the
  144. * <code>attribute_info</code> structure.
  145. * It can be obtained by <code>get()</code>
  146. * in the <code>AttributeInfo</code> class.
  147. */
  148. public Walker(byte[] data) {
  149. info = data;
  150. numOfEntries = ByteArray.readU16bit(data, 0);
  151. }
  152. /**
  153. * Returns the number of the entries.
  154. */
  155. public final int size() { return numOfEntries; }
  156. /**
  157. * Visits each entry of the stack map frames.
  158. */
  159. public void parse() throws BadBytecode {
  160. int n = numOfEntries;
  161. int pos = 2;
  162. for (int i = 0; i < n; i++)
  163. pos = stackMapFrames(pos, i);
  164. }
  165. /**
  166. * Invoked when the next entry of the stack map frames is visited.
  167. *
  168. * @param pos the position of the frame in the <code>info</code>
  169. * field of <code>attribute_info</code> structure.
  170. * @param nth the frame is the N-th
  171. * (0, 1st, 2nd, 3rd, 4th, ...) entry.
  172. * @return the position of the next frame.
  173. */
  174. int stackMapFrames(int pos, int nth) throws BadBytecode {
  175. int type = info[pos] & 0xff;
  176. if (type < 64) {
  177. sameFrame(pos, type);
  178. pos++;
  179. }
  180. else if (type < 128)
  181. pos = sameLocals(pos, type);
  182. else if (type < 247) {
  183. throw new BadBytecode(
  184. "bad frame_type " + type + " in StackMapTable (pos: "
  185. + pos + ", frame no.:" + nth + ")");
  186. }
  187. else if (type == 247) // SAME_LOCALS_1_STACK_ITEM_EXTENDED
  188. pos = sameLocals(pos, type);
  189. else if (type < 251) {
  190. int offset = ByteArray.readU16bit(info, pos + 1);
  191. chopFrame(pos, offset, 251 - type);
  192. pos += 3;
  193. }
  194. else if (type == 251) { // SAME_FRAME_EXTENDED
  195. int offset = ByteArray.readU16bit(info, pos + 1);
  196. sameFrame(pos, offset);
  197. pos += 3;
  198. }
  199. else if (type < 255)
  200. pos = appendFrame(pos, type);
  201. else // FULL_FRAME
  202. pos = fullFrame(pos);
  203. return pos;
  204. }
  205. /**
  206. * Invoked if the visited frame is a <code>same_frame</code> or
  207. * a <code>same_frame_extended</code>.
  208. *
  209. * @param pos the position of this frame in the <code>info</code>
  210. * field of <code>attribute_info</code> structure.
  211. * @param offsetDelta
  212. */
  213. public void sameFrame(int pos, int offsetDelta) throws BadBytecode {}
  214. private int sameLocals(int pos, int type) throws BadBytecode {
  215. int top = pos;
  216. int offset;
  217. if (type < 128)
  218. offset = type - 64;
  219. else { // type == 247
  220. offset = ByteArray.readU16bit(info, pos + 1);
  221. pos += 2;
  222. }
  223. int tag = info[pos + 1] & 0xff;
  224. int data = 0;
  225. if (tag == OBJECT || tag == UNINIT) {
  226. data = ByteArray.readU16bit(info, pos + 2);
  227. objectOrUninitialized(tag, data, pos + 2);
  228. pos += 2;
  229. }
  230. sameLocals(top, offset, tag, data);
  231. return pos + 2;
  232. }
  233. /**
  234. * Invoked if the visited frame is a <code>same_locals_1_stack_item_frame</code>
  235. * or a <code>same_locals_1_stack_item_frame_extended</code>.
  236. *
  237. * @param pos the position.
  238. * @param offsetDelta
  239. * @param stackTag <code>stack[0].tag</code>.
  240. * @param stackData <code>stack[0].cpool_index</code>
  241. * if the tag is <code>OBJECT</code>,
  242. * or <code>stack[0].offset</code>
  243. * if the tag is <code>UNINIT</code>.
  244. */
  245. public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData)
  246. throws BadBytecode {}
  247. /**
  248. * Invoked if the visited frame is a <code>chop_frame</code>.
  249. *
  250. * @param pos the position.
  251. * @param offsetDelta
  252. * @param k the <code>k</code> last locals are absent.
  253. */
  254. public void chopFrame(int pos, int offsetDelta, int k) throws BadBytecode {}
  255. private int appendFrame(int pos, int type) throws BadBytecode {
  256. int k = type - 251;
  257. int offset = ByteArray.readU16bit(info, pos + 1);
  258. int[] tags = new int[k];
  259. int[] data = new int[k];
  260. int p = pos + 3;
  261. for (int i = 0; i < k; i++) {
  262. int tag = info[p] & 0xff;
  263. tags[i] = tag;
  264. if (tag == OBJECT || tag == UNINIT) {
  265. data[i] = ByteArray.readU16bit(info, p + 1);
  266. objectOrUninitialized(tag, data[i], p + 1);
  267. p += 3;
  268. }
  269. else {
  270. data[i] = 0;
  271. p++;
  272. }
  273. }
  274. appendFrame(pos, offset, tags, data);
  275. return p;
  276. }
  277. /**
  278. * Invoked if the visited frame is a <code>append_frame</code>.
  279. *
  280. * @param pos the position.
  281. * @param offsetDelta
  282. * @param tags <code>locals[i].tag</code>.
  283. * @param data <code>locals[i].cpool_index</code>
  284. * or <code>locals[i].offset</code>.
  285. */
  286. public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data)
  287. throws BadBytecode {}
  288. private int fullFrame(int pos) throws BadBytecode {
  289. int offset = ByteArray.readU16bit(info, pos + 1);
  290. int numOfLocals = ByteArray.readU16bit(info, pos + 3);
  291. int[] localsTags = new int[numOfLocals];
  292. int[] localsData = new int[numOfLocals];
  293. int p = verifyTypeInfo(pos + 5, numOfLocals, localsTags, localsData);
  294. int numOfItems = ByteArray.readU16bit(info, p);
  295. int[] itemsTags = new int[numOfItems];
  296. int[] itemsData = new int[numOfItems];
  297. p = verifyTypeInfo(p + 2, numOfItems, itemsTags, itemsData);
  298. fullFrame(pos, offset, localsTags, localsData, itemsTags, itemsData);
  299. return p;
  300. }
  301. /**
  302. * Invoked if the visited frame is <code>full_frame</code>.
  303. *
  304. * @param pos the position.
  305. * @param offsetDelta
  306. * @param localTags <code>locals[i].tag</code>
  307. * @param localData <code>locals[i].cpool_index</code>
  308. * or <code>locals[i].offset</code>
  309. * @param stackTags <code>stack[i].tag</code>
  310. * @param stackData <code>stack[i].cpool_index</code>
  311. * or <code>stack[i].offset</code>
  312. */
  313. public void fullFrame(int pos, int offsetDelta, int[] localTags,
  314. int[] localData, int[] stackTags, int[] stackData)
  315. throws BadBytecode {}
  316. private int verifyTypeInfo(int pos, int n, int[] tags, int[] data) {
  317. for (int i = 0; i < n; i++) {
  318. int tag = info[pos++] & 0xff;
  319. tags[i] = tag;
  320. if (tag == OBJECT || tag == UNINIT) {
  321. data[i] = ByteArray.readU16bit(info, pos);
  322. objectOrUninitialized(tag, data[i], pos);
  323. pos += 2;
  324. }
  325. }
  326. return pos;
  327. }
  328. /**
  329. * Invoked if <code>Object_variable_info</code>
  330. * or <code>Uninitialized_variable_info</code> is visited.
  331. *
  332. * @param tag <code>OBJECT</code> or <code>UNINIT</code>.
  333. * @param data the value of <code>cpool_index</code> or <code>offset</code>.
  334. * @param pos the position of <code>cpool_index</code> or <code>offset</code>.
  335. */
  336. public void objectOrUninitialized(int tag, int data, int pos) {}
  337. }
  338. static class SimpleCopy extends Walker {
  339. private Writer writer;
  340. public SimpleCopy(byte[] data) {
  341. super(data);
  342. writer = new Writer(data.length);
  343. }
  344. public byte[] doit() throws BadBytecode {
  345. parse();
  346. return writer.toByteArray();
  347. }
  348. @Override
  349. public void sameFrame(int pos, int offsetDelta) {
  350. writer.sameFrame(offsetDelta);
  351. }
  352. @Override
  353. public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
  354. writer.sameLocals(offsetDelta, stackTag, copyData(stackTag, stackData));
  355. }
  356. @Override
  357. public void chopFrame(int pos, int offsetDelta, int k) {
  358. writer.chopFrame(offsetDelta, k);
  359. }
  360. @Override
  361. public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {
  362. writer.appendFrame(offsetDelta, tags, copyData(tags, data));
  363. }
  364. @Override
  365. public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
  366. int[] stackTags, int[] stackData) {
  367. writer.fullFrame(offsetDelta, localTags, copyData(localTags, localData),
  368. stackTags, copyData(stackTags, stackData));
  369. }
  370. protected int copyData(int tag, int data) {
  371. return data;
  372. }
  373. protected int[] copyData(int[] tags, int[] data) {
  374. return data;
  375. }
  376. }
  377. static class Copier extends SimpleCopy {
  378. private ConstPool srcPool, destPool;
  379. private Map<String,String> classnames;
  380. public Copier(ConstPool src, byte[] data, ConstPool dest, Map<String,String> names) {
  381. super(data);
  382. srcPool = src;
  383. destPool = dest;
  384. classnames = names;
  385. }
  386. @Override
  387. protected int copyData(int tag, int data) {
  388. if (tag == OBJECT)
  389. return srcPool.copy(data, destPool, classnames);
  390. return data;
  391. }
  392. @Override
  393. protected int[] copyData(int[] tags, int[] data) {
  394. int[] newData = new int[data.length];
  395. for (int i = 0; i < data.length; i++)
  396. if (tags[i] == OBJECT)
  397. newData[i] = srcPool.copy(data[i], destPool, classnames);
  398. else
  399. newData[i] = data[i];
  400. return newData;
  401. }
  402. }
  403. /**
  404. * Updates this stack map table when a new local variable is inserted
  405. * for a new parameter.
  406. *
  407. * @param index the index of the added local variable.
  408. * @param tag the type tag of that local variable.
  409. * @param classInfo the index of the <code>CONSTANT_Class_info</code> structure
  410. * in a constant pool table. This should be zero unless the tag
  411. * is <code>ITEM_Object</code>.
  412. *
  413. * @see javassist.CtBehavior#addParameter(javassist.CtClass)
  414. * @see #typeTagOf(char)
  415. * @see ConstPool
  416. */
  417. public void insertLocal(int index, int tag, int classInfo)
  418. throws BadBytecode
  419. {
  420. byte[] data = new InsertLocal(this.get(), index, tag, classInfo).doit();
  421. this.set(data);
  422. }
  423. /**
  424. * Returns the tag of the type specified by the
  425. * descriptor. This method returns <code>INTEGER</code>
  426. * unless the descriptor is either D (double), F (float),
  427. * J (long), L (class type), or [ (array).
  428. *
  429. * @param descriptor the type descriptor.
  430. * @see Descriptor
  431. */
  432. public static int typeTagOf(char descriptor) {
  433. switch (descriptor) {
  434. case 'D' :
  435. return DOUBLE;
  436. case 'F' :
  437. return FLOAT;
  438. case 'J' :
  439. return LONG;
  440. case 'L' :
  441. case '[' :
  442. return OBJECT;
  443. // case 'V' :
  444. default :
  445. return INTEGER;
  446. }
  447. }
  448. /* This implementation assumes that a local variable initially
  449. * holding a parameter value is never changed to be a different
  450. * type.
  451. *
  452. */
  453. static class InsertLocal extends SimpleCopy {
  454. private int varIndex;
  455. private int varTag, varData;
  456. public InsertLocal(byte[] data, int varIndex, int varTag, int varData) {
  457. super(data);
  458. this.varIndex = varIndex;
  459. this.varTag = varTag;
  460. this.varData = varData;
  461. }
  462. @Override
  463. public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
  464. int[] stackTags, int[] stackData) {
  465. int len = localTags.length;
  466. if (len < varIndex) {
  467. super.fullFrame(pos, offsetDelta, localTags, localData, stackTags, stackData);
  468. return;
  469. }
  470. int typeSize = (varTag == LONG || varTag == DOUBLE) ? 2 : 1;
  471. int[] localTags2 = new int[len + typeSize];
  472. int[] localData2 = new int[len + typeSize];
  473. int index = varIndex;
  474. int j = 0;
  475. for (int i = 0; i < len; i++) {
  476. if (j == index)
  477. j += typeSize;
  478. localTags2[j] = localTags[i];
  479. localData2[j++] = localData[i];
  480. }
  481. localTags2[index] = varTag;
  482. localData2[index] = varData;
  483. if (typeSize > 1) {
  484. localTags2[index + 1] = TOP;
  485. localData2[index + 1] = 0;
  486. }
  487. super.fullFrame(pos, offsetDelta, localTags2, localData2, stackTags, stackData);
  488. }
  489. }
  490. /**
  491. * A writer of stack map tables.
  492. */
  493. public static class Writer {
  494. ByteArrayOutputStream output;
  495. int numOfEntries;
  496. /**
  497. * Constructs a writer.
  498. * @param size the initial buffer size.
  499. */
  500. public Writer(int size) {
  501. output = new ByteArrayOutputStream(size);
  502. numOfEntries = 0;
  503. output.write(0); // u2 number_of_entries
  504. output.write(0);
  505. }
  506. /**
  507. * Returns the stack map table written out.
  508. */
  509. public byte[] toByteArray() {
  510. byte[] b = output.toByteArray();
  511. ByteArray.write16bit(numOfEntries, b, 0);
  512. return b;
  513. }
  514. /**
  515. * Constructs and a return a stack map table containing
  516. * the written stack map entries.
  517. *
  518. * @param cp the constant pool used to write
  519. * the stack map entries.
  520. */
  521. public StackMapTable toStackMapTable(ConstPool cp) {
  522. return new StackMapTable(cp, toByteArray());
  523. }
  524. /**
  525. * Writes a <code>same_frame</code> or a <code>same_frame_extended</code>.
  526. */
  527. public void sameFrame(int offsetDelta) {
  528. numOfEntries++;
  529. if (offsetDelta < 64)
  530. output.write(offsetDelta);
  531. else {
  532. output.write(251); // SAME_FRAME_EXTENDED
  533. write16(offsetDelta);
  534. }
  535. }
  536. /**
  537. * Writes a <code>same_locals_1_stack_item</code>
  538. * or a <code>same_locals_1_stack_item_extended</code>.
  539. *
  540. * @param tag <code>stack[0].tag</code>.
  541. * @param data <code>stack[0].cpool_index</code>
  542. * if the tag is <code>OBJECT</code>,
  543. * or <code>stack[0].offset</code>
  544. * if the tag is <code>UNINIT</code>.
  545. * Otherwise, this parameter is not used.
  546. */
  547. public void sameLocals(int offsetDelta, int tag, int data) {
  548. numOfEntries++;
  549. if (offsetDelta < 64)
  550. output.write(offsetDelta + 64);
  551. else {
  552. output.write(247); // SAME_LOCALS_1_STACK_ITEM_EXTENDED
  553. write16(offsetDelta);
  554. }
  555. writeTypeInfo(tag, data);
  556. }
  557. /**
  558. * Writes a <code>chop_frame</code>.
  559. *
  560. * @param k the number of absent locals. 1, 2, or 3.
  561. */
  562. public void chopFrame(int offsetDelta, int k) {
  563. numOfEntries++;
  564. output.write(251 - k);
  565. write16(offsetDelta);
  566. }
  567. /**
  568. * Writes a <code>append_frame</code>. The number of the appended
  569. * locals is specified by the length of <code>tags</code>.
  570. *
  571. * @param tags <code>locals[].tag</code>.
  572. * The length of this array must be
  573. * either 1, 2, or 3.
  574. * @param data <code>locals[].cpool_index</code>
  575. * if the tag is <code>OBJECT</code>,
  576. * or <code>locals[].offset</code>
  577. * if the tag is <code>UNINIT</code>.
  578. * Otherwise, this parameter is not used.
  579. */
  580. public void appendFrame(int offsetDelta, int[] tags, int[] data) {
  581. numOfEntries++;
  582. int k = tags.length; // k is 1, 2, or 3
  583. output.write(k + 251);
  584. write16(offsetDelta);
  585. for (int i = 0; i < k; i++)
  586. writeTypeInfo(tags[i], data[i]);
  587. }
  588. /**
  589. * Writes a <code>full_frame</code>.
  590. * <code>number_of_locals</code> and <code>number_of_stack_items</code>
  591. * are specified by the the length of <code>localTags</code> and
  592. * <code>stackTags</code>.
  593. *
  594. * @param localTags <code>locals[].tag</code>.
  595. * @param localData <code>locals[].cpool_index</code>
  596. * if the tag is <code>OBJECT</code>,
  597. * or <code>locals[].offset</code>
  598. * if the tag is <code>UNINIT</code>.
  599. * Otherwise, this parameter is not used.
  600. * @param stackTags <code>stack[].tag</code>.
  601. * @param stackData <code>stack[].cpool_index</code>
  602. * if the tag is <code>OBJECT</code>,
  603. * or <code>stack[].offset</code>
  604. * if the tag is <code>UNINIT</code>.
  605. * Otherwise, this parameter is not used.
  606. */
  607. public void fullFrame(int offsetDelta, int[] localTags, int[] localData,
  608. int[] stackTags, int[] stackData) {
  609. numOfEntries++;
  610. output.write(255); // FULL_FRAME
  611. write16(offsetDelta);
  612. int n = localTags.length;
  613. write16(n);
  614. for (int i = 0; i < n; i++)
  615. writeTypeInfo(localTags[i], localData[i]);
  616. n = stackTags.length;
  617. write16(n);
  618. for (int i = 0; i < n; i++)
  619. writeTypeInfo(stackTags[i], stackData[i]);
  620. }
  621. private void writeTypeInfo(int tag, int data) {
  622. output.write(tag);
  623. if (tag == OBJECT || tag == UNINIT)
  624. write16(data);
  625. }
  626. private void write16(int value) {
  627. output.write((value >>> 8) & 0xff);
  628. output.write(value & 0xff);
  629. }
  630. }
  631. /**
  632. * Prints the stack table map.
  633. */
  634. public void println(PrintWriter w) {
  635. Printer.print(this, w);
  636. }
  637. /**
  638. * Prints the stack table map.
  639. *
  640. * @param ps a print stream such as <code>System.out</code>.
  641. */
  642. public void println(java.io.PrintStream ps) {
  643. Printer.print(this, new java.io.PrintWriter(ps, true));
  644. }
  645. static class Printer extends Walker {
  646. private PrintWriter writer;
  647. private int offset;
  648. /**
  649. * Prints the stack table map.
  650. */
  651. public static void print(StackMapTable smt, PrintWriter writer) {
  652. try {
  653. new Printer(smt.get(), writer).parse();
  654. }
  655. catch (BadBytecode e) {
  656. writer.println(e.getMessage());
  657. }
  658. }
  659. Printer(byte[] data, PrintWriter pw) {
  660. super(data);
  661. writer = pw;
  662. offset = -1;
  663. }
  664. @Override
  665. public void sameFrame(int pos, int offsetDelta) {
  666. offset += offsetDelta + 1;
  667. writer.println(offset + " same frame: " + offsetDelta);
  668. }
  669. @Override
  670. public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
  671. offset += offsetDelta + 1;
  672. writer.println(offset + " same locals: " + offsetDelta);
  673. printTypeInfo(stackTag, stackData);
  674. }
  675. @Override
  676. public void chopFrame(int pos, int offsetDelta, int k) {
  677. offset += offsetDelta + 1;
  678. writer.println(offset + " chop frame: " + offsetDelta + ", " + k + " last locals");
  679. }
  680. @Override
  681. public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {
  682. offset += offsetDelta + 1;
  683. writer.println(offset + " append frame: " + offsetDelta);
  684. for (int i = 0; i < tags.length; i++)
  685. printTypeInfo(tags[i], data[i]);
  686. }
  687. @Override
  688. public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
  689. int[] stackTags, int[] stackData) {
  690. offset += offsetDelta + 1;
  691. writer.println(offset + " full frame: " + offsetDelta);
  692. writer.println("[locals]");
  693. for (int i = 0; i < localTags.length; i++)
  694. printTypeInfo(localTags[i], localData[i]);
  695. writer.println("[stack]");
  696. for (int i = 0; i < stackTags.length; i++)
  697. printTypeInfo(stackTags[i], stackData[i]);
  698. }
  699. private void printTypeInfo(int tag, int data) {
  700. String msg = null;
  701. switch (tag) {
  702. case TOP :
  703. msg = "top";
  704. break;
  705. case INTEGER :
  706. msg = "integer";
  707. break;
  708. case FLOAT :
  709. msg = "float";
  710. break;
  711. case DOUBLE :
  712. msg = "double";
  713. break;
  714. case LONG :
  715. msg = "long";
  716. break;
  717. case NULL :
  718. msg = "null";
  719. break;
  720. case THIS :
  721. msg = "this";
  722. break;
  723. case OBJECT :
  724. msg = "object (cpool_index " + data + ")";
  725. break;
  726. case UNINIT :
  727. msg = "uninitialized (offset " + data + ")";
  728. break;
  729. }
  730. writer.print(" ");
  731. writer.println(msg);
  732. }
  733. }
  734. void shiftPc(int where, int gapSize, boolean exclusive)
  735. throws BadBytecode
  736. {
  737. new OffsetShifter(this, where, gapSize).parse();
  738. new Shifter(this, where, gapSize, exclusive).doit();
  739. }
  740. static class OffsetShifter extends Walker {
  741. int where, gap;
  742. public OffsetShifter(StackMapTable smt, int where, int gap) {
  743. super(smt);
  744. this.where = where;
  745. this.gap = gap;
  746. }
  747. @Override
  748. public void objectOrUninitialized(int tag, int data, int pos) {
  749. if (tag == UNINIT)
  750. if (where <= data)
  751. ByteArray.write16bit(data + gap, info, pos);
  752. }
  753. }
  754. static class Shifter extends Walker {
  755. private StackMapTable stackMap;
  756. int where, gap;
  757. int position;
  758. byte[] updatedInfo;
  759. boolean exclusive;
  760. public Shifter(StackMapTable smt, int where, int gap, boolean exclusive) {
  761. super(smt);
  762. stackMap = smt;
  763. this.where = where;
  764. this.gap = gap;
  765. this.position = 0;
  766. this.updatedInfo = null;
  767. this.exclusive = exclusive;
  768. }
  769. public void doit() throws BadBytecode {
  770. parse();
  771. if (updatedInfo != null)
  772. stackMap.set(updatedInfo);
  773. }
  774. @Override
  775. public void sameFrame(int pos, int offsetDelta) {
  776. update(pos, offsetDelta, 0, 251);
  777. }
  778. @Override
  779. public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
  780. update(pos, offsetDelta, 64, 247);
  781. }
  782. void update(int pos, int offsetDelta, int base, int entry) {
  783. int oldPos = position;
  784. position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
  785. boolean match;
  786. if (exclusive)
  787. // We optimize this expression by hand:
  788. // match = (oldPos == 0 && where == 0 && (0 < position || 0 == position))
  789. // || oldPos < where && where <= position;
  790. match = (oldPos == 0 && where == 0)
  791. || oldPos < where && where <= position;
  792. else
  793. match = oldPos <= where && where < position;
  794. if (match) {
  795. int current = info[pos] & 0xff;
  796. int newDelta = offsetDelta + gap;
  797. position += gap;
  798. if (newDelta < 64)
  799. info[pos] = (byte)(newDelta + base);
  800. else if (offsetDelta < 64 && current != entry) {
  801. byte[] newinfo = insertGap(info, pos, 2);
  802. newinfo[pos] = (byte)entry;
  803. ByteArray.write16bit(newDelta, newinfo, pos + 1);
  804. updatedInfo = newinfo;
  805. }
  806. else
  807. ByteArray.write16bit(newDelta, info, pos + 1);
  808. }
  809. }
  810. static byte[] insertGap(byte[] info, int where, int gap) {
  811. int len = info.length;
  812. byte[] newinfo = new byte[len + gap];
  813. if (where <= 0) {
  814. System.arraycopy(info, 0, newinfo, gap, len);
  815. } else if (where >= len) {
  816. System.arraycopy(info, 0, newinfo, 0, len);
  817. } else {
  818. assert (where > 0 && where < len);
  819. System.arraycopy(info, 0, newinfo, 0, where);
  820. System.arraycopy(info, where, newinfo, where + gap, len - where);
  821. }
  822. return newinfo;
  823. }
  824. @Override
  825. public void chopFrame(int pos, int offsetDelta, int k) {
  826. update(pos, offsetDelta);
  827. }
  828. @Override
  829. public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {
  830. update(pos, offsetDelta);
  831. }
  832. @Override
  833. public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
  834. int[] stackTags, int[] stackData) {
  835. update(pos, offsetDelta);
  836. }
  837. void update(int pos, int offsetDelta) {
  838. int oldPos = position;
  839. position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
  840. boolean match;
  841. if (exclusive)
  842. match = (oldPos == 0 && where == 0)
  843. || oldPos < where && where <= position;
  844. else
  845. match = oldPos <= where && where < position;
  846. if (match) {
  847. int newDelta = offsetDelta + gap;
  848. ByteArray.write16bit(newDelta, info, pos + 1);
  849. position += gap;
  850. }
  851. }
  852. }
  853. /**
  854. * @see CodeIterator.Switcher#adjustOffsets(int, int)
  855. */
  856. void shiftForSwitch(int where, int gapSize) throws BadBytecode {
  857. new SwitchShifter(this, where, gapSize).doit();
  858. }
  859. static class SwitchShifter extends Shifter {
  860. SwitchShifter(StackMapTable smt, int where, int gap) {
  861. super(smt, where, gap, false);
  862. }
  863. @Override
  864. void update(int pos, int offsetDelta, int base, int entry) {
  865. int oldPos = position;
  866. position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
  867. int newDelta = offsetDelta;
  868. if (where == position)
  869. newDelta = offsetDelta - gap;
  870. else if (where == oldPos)
  871. newDelta = offsetDelta + gap;
  872. else
  873. return;
  874. if (offsetDelta < 64)
  875. if (newDelta < 64)
  876. info[pos] = (byte)(newDelta + base);
  877. else {
  878. byte[] newinfo = insertGap(info, pos, 2);
  879. newinfo[pos] = (byte)entry;
  880. ByteArray.write16bit(newDelta, newinfo, pos + 1);
  881. updatedInfo = newinfo;
  882. }
  883. else
  884. if (newDelta < 64) {
  885. byte[] newinfo = deleteGap(info, pos, 2);
  886. newinfo[pos] = (byte)(newDelta + base);
  887. updatedInfo = newinfo;
  888. }
  889. else
  890. ByteArray.write16bit(newDelta, info, pos + 1);
  891. }
  892. static byte[] deleteGap(byte[] info, int where, int gap) {
  893. where += gap;
  894. int len = info.length;
  895. byte[] newinfo = new byte[len - gap];
  896. for (int i = 0; i < len; i++)
  897. newinfo[i - (i < where ? 0 : gap)] = info[i];
  898. return newinfo;
  899. }
  900. @Override
  901. void update(int pos, int offsetDelta) {
  902. int oldPos = position;
  903. position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
  904. int newDelta = offsetDelta;
  905. if (where == position)
  906. newDelta = offsetDelta - gap;
  907. else if (where == oldPos)
  908. newDelta = offsetDelta + gap;
  909. else
  910. return;
  911. ByteArray.write16bit(newDelta, info, pos + 1);
  912. }
  913. }
  914. /**
  915. * Undocumented method. Do not use; internal-use only.
  916. *
  917. * <p>This method is for javassist.convert.TransformNew.
  918. * It is called to update the stack map table when
  919. * the NEW opcode (and the following DUP) is removed.
  920. *
  921. * @param where the position of the removed NEW opcode.
  922. */
  923. public void removeNew(int where) throws CannotCompileException {
  924. try {
  925. byte[] data = new NewRemover(this.get(), where).doit();
  926. this.set(data);
  927. }
  928. catch (BadBytecode e) {
  929. throw new CannotCompileException("bad stack map table", e);
  930. }
  931. }
  932. static class NewRemover extends SimpleCopy {
  933. int posOfNew;
  934. public NewRemover(byte[] data, int pos) {
  935. super(data);
  936. posOfNew = pos;
  937. }
  938. @Override
  939. public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
  940. if (stackTag == UNINIT && stackData == posOfNew)
  941. super.sameFrame(pos, offsetDelta);
  942. else
  943. super.sameLocals(pos, offsetDelta, stackTag, stackData);
  944. }
  945. @Override
  946. public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
  947. int[] stackTags, int[] stackData) {
  948. int n = stackTags.length - 1;
  949. for (int i = 0; i < n; i++)
  950. if (stackTags[i] == UNINIT && stackData[i] == posOfNew
  951. && stackTags[i + 1] == UNINIT && stackData[i + 1] == posOfNew) {
  952. n++;
  953. int[] stackTags2 = new int[n - 2];
  954. int[] stackData2 = new int[n - 2];
  955. int k = 0;
  956. for (int j = 0; j < n; j++)
  957. if (j == i)
  958. j++;
  959. else {
  960. stackTags2[k] = stackTags[j];
  961. stackData2[k++] = stackData[j];
  962. }
  963. stackTags = stackTags2;
  964. stackData = stackData2;
  965. break;
  966. }
  967. super.fullFrame(pos, offsetDelta, localTags, localData, stackTags, stackData);
  968. }
  969. }
  970. }