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

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