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

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