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.

InstructionList.java 37KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286
  1. package org.aspectj.apache.bcel.generic;
  2. /* ====================================================================
  3. * The Apache Software License, Version 1.1
  4. *
  5. * Copyright (c) 2001 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Apache" and "Apache Software Foundation" and
  28. * "Apache BCEL" must not be used to endorse or promote products
  29. * derived from this software without prior written permission. For
  30. * written permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * "Apache BCEL", nor may "Apache" appear in their name, without
  34. * prior written permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation. For more
  52. * information on the Apache Software Foundation, please see
  53. * <http://www.apache.org/>.
  54. */
  55. import java.io.ByteArrayOutputStream;
  56. import java.io.DataOutputStream;
  57. import java.io.IOException;
  58. import java.io.Serializable;
  59. import java.util.ArrayList;
  60. import java.util.HashMap;
  61. import java.util.Iterator;
  62. import java.util.List;
  63. import java.util.Set;
  64. import org.aspectj.apache.bcel.Constants;
  65. import org.aspectj.apache.bcel.classfile.Constant;
  66. import org.aspectj.apache.bcel.classfile.ConstantPool;
  67. import org.aspectj.apache.bcel.util.ByteSequence;
  68. /**
  69. * This class is a container for a list of <a href="Instruction.html">Instruction</a> objects. Instructions can be appended,
  70. * inserted, moved, deleted, etc.. Instructions are being wrapped into <a href="InstructionHandle.html">InstructionHandles</a>
  71. * objects that are returned upon append/insert operations. They give the user (read only) access to the list structure, such that
  72. * it can be traversed and manipulated in a controlled way.
  73. *
  74. * A list is finally dumped to a byte code array with <a href="#getByteCode()">getByteCode</a>.
  75. *
  76. * @version $Id: InstructionList.java,v 1.12 2011/09/02 22:33:04 aclement Exp $
  77. * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  78. * @author Abraham Nevado
  79. * @see Instruction
  80. * @see InstructionHandle
  81. * @see BranchHandle
  82. */
  83. public class InstructionList implements Serializable {
  84. private InstructionHandle start = null, end = null;
  85. private int length = 0;
  86. private int[] positions; // byte code offsets corresponding to instructions
  87. public InstructionList() {
  88. }
  89. public InstructionList(Instruction i) {
  90. append(i);
  91. }
  92. public boolean isEmpty() {
  93. return start == null;
  94. } // && end == null
  95. public static InstructionHandle findHandle(InstructionHandle[] ihs, int[] pos, int count, int target) {
  96. return findHandle(ihs, pos, count, target, false);
  97. }
  98. /**
  99. * Find the target instruction (handle) that corresponds to the given target position (byte code offset).
  100. *
  101. * @param ihs array of instruction handles, i.e. il.getInstructionHandles()
  102. * @param pos array of positions corresponding to ihs, i.e. il.getInstructionPositions()
  103. * @param count length of arrays
  104. * @param target target position to search for
  105. * @return target position's instruction handle if available
  106. */
  107. public static InstructionHandle findHandle(InstructionHandle[] ihs, int[] pos, int count, int target,
  108. boolean returnClosestIfNoExactMatch) {
  109. int l = 0, r = count - 1;
  110. // Do a binary search since the pos array is ordered
  111. int i, j;
  112. do {
  113. i = (l + r) / 2;
  114. j = pos[i];
  115. if (j == target) {
  116. return ihs[i]; // found it
  117. } else if (target < j) {
  118. r = i - 1; // else constrain search area
  119. } else {
  120. l = i + 1; // target > j
  121. }
  122. } while (l <= r);
  123. if (returnClosestIfNoExactMatch) {
  124. i = (l + r) / 2;
  125. if (i < 0) {
  126. i = 0;
  127. }
  128. return ihs[i];
  129. }
  130. return null;
  131. }
  132. /**
  133. * Get instruction handle for instruction at byte code position pos. This only works properly, if the list is freshly
  134. * initialized from a byte array or setPositions() has been called before this method.
  135. *
  136. * @param pos byte code position to search for
  137. * @return target position's instruction handle if available
  138. */
  139. public InstructionHandle findHandle(int pos) {
  140. InstructionHandle[] ihs = getInstructionHandles();
  141. return findHandle(ihs, positions, length, pos);
  142. }
  143. public InstructionHandle[] getInstructionsAsArray() {
  144. return getInstructionHandles();
  145. }
  146. public InstructionHandle findHandle(int pos, InstructionHandle[] instructionArray) {
  147. return findHandle(instructionArray, positions, length, pos);
  148. }
  149. public InstructionHandle findHandle(int pos, InstructionHandle[] instructionArray, boolean useClosestApproximationIfNoExactFound) {
  150. return findHandle(instructionArray, positions, length, pos, useClosestApproximationIfNoExactFound);
  151. }
  152. /**
  153. * Initialize instruction list from byte array.
  154. *
  155. * @param code byte array containing the instructions
  156. */
  157. public InstructionList(byte[] code) {
  158. ByteSequence bytes = new ByteSequence(code);
  159. InstructionHandle[] ihs = new InstructionHandle[code.length];
  160. int[] pos = new int[code.length]; // Can't be more than that
  161. int count = 0; // Contains actual length
  162. /*
  163. * Pass 1: Create an object for each byte code and append them to the list.
  164. */
  165. try {
  166. while (bytes.available() > 0) {
  167. // Remember byte offset and associate it with the instruction
  168. int off = bytes.getIndex();
  169. pos[count] = off;
  170. /*
  171. * Read one instruction from the byte stream, the byte position is set accordingly.
  172. */
  173. Instruction i = Instruction.readInstruction(bytes);
  174. InstructionHandle ih;
  175. if (i instanceof InstructionBranch) {
  176. ih = append((InstructionBranch) i);
  177. } else {
  178. ih = append(i);
  179. }
  180. ih.setPosition(off);
  181. ihs[count] = ih;
  182. count++;
  183. }
  184. } catch (IOException e) {
  185. throw new ClassGenException(e.toString());
  186. }
  187. positions = new int[count]; // Trim to proper size
  188. System.arraycopy(pos, 0, positions, 0, count);
  189. /*
  190. * Pass 2: Look for BranchInstruction and update their targets, i.e., convert offsets to instruction handles.
  191. */
  192. // OPTIMIZE better way of doing this? keep little map from earlier from pos -> instruction handle?
  193. for (int i = 0; i < count; i++) {
  194. if (ihs[i] instanceof BranchHandle) {
  195. InstructionBranch bi = (InstructionBranch) ihs[i].instruction;
  196. int target = bi.positionOfThisInstruction + bi.getIndex(); /*
  197. * Byte code position: relative -> absolute.
  198. */
  199. // Search for target position
  200. InstructionHandle ih = findHandle(ihs, pos, count, target);
  201. if (ih == null) {
  202. throw new ClassGenException("Couldn't find target for branch: " + bi);
  203. }
  204. bi.setTarget(ih); // Update target
  205. // If it is a Select instruction, update all branch targets
  206. if (bi instanceof InstructionSelect) { // Either LOOKUPSWITCH or TABLESWITCH
  207. InstructionSelect s = (InstructionSelect) bi;
  208. int[] indices = s.getIndices();
  209. for (int j = 0; j < indices.length; j++) {
  210. target = bi.positionOfThisInstruction + indices[j];
  211. ih = findHandle(ihs, pos, count, target);
  212. if (ih == null) {
  213. throw new ClassGenException("Couldn't find target for switch: " + bi);
  214. }
  215. s.setTarget(j, ih); // Update target
  216. }
  217. }
  218. }
  219. }
  220. }
  221. /**
  222. * Append another list after instruction (handle) ih contained in this list. Consumes argument list, i.e., it becomes empty.
  223. *
  224. * @param appendTo where to append the instruction list
  225. * @param appendee Instruction list to append to this one
  226. * @return instruction handle pointing to the <B>first</B> appended instruction
  227. */
  228. public InstructionHandle append(InstructionHandle appendTo, InstructionList appendee) {
  229. assert appendee != null;
  230. if (appendee.isEmpty()) {
  231. return appendTo;
  232. }
  233. InstructionHandle next = appendTo.next;
  234. InstructionHandle ret = appendee.start;
  235. appendTo.next = appendee.start;
  236. appendee.start.prev = appendTo;
  237. appendee.end.next = next;
  238. if (next != null) {
  239. next.prev = appendee.end;
  240. } else {
  241. end = appendee.end; // Update end ...
  242. }
  243. length += appendee.length; // Update length
  244. appendee.clear();
  245. return ret;
  246. }
  247. /**
  248. * Append another list after instruction i contained in this list. Consumes argument list, i.e., it becomes empty.
  249. *
  250. * @param i where to append the instruction list
  251. * @param il Instruction list to append to this one
  252. * @return instruction handle pointing to the <B>first</B> appended instruction
  253. */
  254. public InstructionHandle append(Instruction i, InstructionList il) {
  255. InstructionHandle ih;
  256. if ((ih = findInstruction2(i)) == null) {
  257. throw new ClassGenException("Instruction " + i + " is not contained in this list.");
  258. }
  259. return append(ih, il);
  260. }
  261. /**
  262. * Append another list to this one. Consumes argument list, i.e., it becomes empty.
  263. *
  264. * @param il list to append to end of this list
  265. * @return instruction handle of the <B>first</B> appended instruction
  266. */
  267. public InstructionHandle append(InstructionList il) {
  268. assert il != null;
  269. if (il.isEmpty()) {
  270. return null;
  271. }
  272. if (isEmpty()) {
  273. start = il.start;
  274. end = il.end;
  275. length = il.length;
  276. il.clear();
  277. return start;
  278. } else {
  279. return append(end, il); // was end.instruction
  280. }
  281. }
  282. /**
  283. * Append an instruction to the end of this list.
  284. *
  285. * @param ih instruction to append
  286. */
  287. private void append(InstructionHandle ih) {
  288. if (isEmpty()) {
  289. start = end = ih;
  290. ih.next = ih.prev = null;
  291. } else {
  292. end.next = ih;
  293. ih.prev = end;
  294. ih.next = null;
  295. end = ih;
  296. }
  297. length++; // Update length
  298. }
  299. /**
  300. * Append an instruction to the end of this list.
  301. *
  302. * @param i instruction to append
  303. * @return instruction handle of the appended instruction
  304. */
  305. public InstructionHandle append(Instruction i) {
  306. InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
  307. append(ih);
  308. return ih;
  309. }
  310. public InstructionHandle appendDUP() {
  311. InstructionHandle ih = InstructionHandle.getInstructionHandle(InstructionConstants.DUP);
  312. append(ih);
  313. return ih;
  314. }
  315. public InstructionHandle appendNOP() {
  316. InstructionHandle ih = InstructionHandle.getInstructionHandle(InstructionConstants.NOP);
  317. append(ih);
  318. return ih;
  319. }
  320. public InstructionHandle appendPOP() {
  321. InstructionHandle ih = InstructionHandle.getInstructionHandle(InstructionConstants.POP);
  322. append(ih);
  323. return ih;
  324. }
  325. /**
  326. * Append a branch instruction to the end of this list.
  327. *
  328. * @param i branch instruction to append
  329. * @return branch instruction handle of the appended instruction
  330. */
  331. public BranchHandle append(InstructionBranch i) {
  332. BranchHandle ih = BranchHandle.getBranchHandle(i);
  333. append(ih);
  334. return ih;
  335. }
  336. /**
  337. * Append a single instruction j after another instruction i, which must be in this list of course!
  338. *
  339. * @param i Instruction in list
  340. * @param j Instruction to append after i in list
  341. * @return instruction handle of the first appended instruction
  342. */
  343. public InstructionHandle append(Instruction i, Instruction j) {
  344. return append(i, new InstructionList(j));
  345. }
  346. /**
  347. * Append an instruction after instruction (handle) ih contained in this list.
  348. *
  349. * @param ih where to append the instruction list
  350. * @param i Instruction to append
  351. * @return instruction handle pointing to the <B>first</B> appended instruction
  352. */
  353. public InstructionHandle append(InstructionHandle ih, Instruction i) {
  354. return append(ih, new InstructionList(i));
  355. }
  356. /**
  357. * Append an instruction after instruction (handle) ih contained in this list.
  358. *
  359. * @param ih where to append the instruction list
  360. * @param i Instruction to append
  361. * @return instruction handle pointing to the <B>first</B> appended instruction
  362. */
  363. public BranchHandle append(InstructionHandle ih, InstructionBranch i) {
  364. BranchHandle bh = BranchHandle.getBranchHandle(i);
  365. InstructionList il = new InstructionList();
  366. il.append(bh);
  367. append(ih, il);
  368. return bh;
  369. }
  370. /**
  371. * Insert another list before Instruction handle ih contained in this list. Consumes argument list, i.e., it becomes empty.
  372. *
  373. * @param i where to append the instruction list
  374. * @param il Instruction list to insert
  375. * @return instruction handle of the first inserted instruction
  376. */
  377. public InstructionHandle insert(InstructionHandle ih, InstructionList il) {
  378. if (il == null) {
  379. throw new ClassGenException("Inserting null InstructionList");
  380. }
  381. if (il.isEmpty()) {
  382. return ih;
  383. }
  384. InstructionHandle prev = ih.prev, ret = il.start;
  385. ih.prev = il.end;
  386. il.end.next = ih;
  387. il.start.prev = prev;
  388. if (prev != null) {
  389. prev.next = il.start;
  390. } else {
  391. start = il.start; // Update start ...
  392. }
  393. length += il.length; // Update length
  394. il.clear();
  395. return ret;
  396. }
  397. /**
  398. * Insert another list.
  399. *
  400. * @param il list to insert before start of this list
  401. * @return instruction handle of the first inserted instruction
  402. */
  403. public InstructionHandle insert(InstructionList il) {
  404. if (isEmpty()) {
  405. append(il); // Code is identical for this case
  406. return start;
  407. } else {
  408. return insert(start, il);
  409. }
  410. }
  411. /**
  412. * Insert an instruction at start of this list.
  413. *
  414. * @param ih instruction to insert
  415. */
  416. private void insert(InstructionHandle ih) {
  417. if (isEmpty()) {
  418. start = end = ih;
  419. ih.next = ih.prev = null;
  420. } else {
  421. start.prev = ih;
  422. ih.next = start;
  423. ih.prev = null;
  424. start = ih;
  425. }
  426. length++;
  427. }
  428. /**
  429. * Insert another list before Instruction i contained in this list. Consumes argument list, i.e., it becomes empty.
  430. *
  431. * @param i where to append the instruction list
  432. * @param il Instruction list to insert
  433. * @return instruction handle pointing to the first inserted instruction, i.e., il.getStart()
  434. */
  435. public InstructionHandle insert(Instruction i, InstructionList il) {
  436. InstructionHandle ih;
  437. if ((ih = findInstruction1(i)) == null) {
  438. throw new ClassGenException("Instruction " + i + " is not contained in this list.");
  439. }
  440. return insert(ih, il);
  441. }
  442. /**
  443. * Insert an instruction at start of this list.
  444. *
  445. * @param i instruction to insert
  446. * @return instruction handle of the inserted instruction
  447. */
  448. public InstructionHandle insert(Instruction i) {
  449. InstructionHandle ih = InstructionHandle.getInstructionHandle(i);
  450. insert(ih);
  451. return ih;
  452. }
  453. /**
  454. * Insert a branch instruction at start of this list.
  455. *
  456. * @param i branch instruction to insert
  457. * @return branch instruction handle of the appended instruction
  458. */
  459. public BranchHandle insert(InstructionBranch i) {
  460. BranchHandle ih = BranchHandle.getBranchHandle(i);
  461. insert(ih);
  462. return ih;
  463. }
  464. /**
  465. * Insert a single instruction j before another instruction i, which must be in this list of course!
  466. *
  467. * @param i Instruction in list
  468. * @param j Instruction to insert before i in list
  469. * @return instruction handle of the first inserted instruction
  470. */
  471. public InstructionHandle insert(Instruction i, Instruction j) {
  472. return insert(i, new InstructionList(j));
  473. }
  474. /**
  475. * Insert an instruction before instruction (handle) ih contained in this list.
  476. *
  477. * @param ih where to insert to the instruction list
  478. * @param i Instruction to insert
  479. * @return instruction handle of the first inserted instruction
  480. */
  481. public InstructionHandle insert(InstructionHandle ih, Instruction i) {
  482. return insert(ih, new InstructionList(i));
  483. }
  484. /**
  485. * Insert an instruction before instruction (handle) ih contained in this list.
  486. *
  487. * @param ih where to insert to the instruction list
  488. * @param i Instruction to insert
  489. * @return instruction handle of the first inserted instruction
  490. */
  491. public BranchHandle insert(InstructionHandle ih, InstructionBranch i) {
  492. BranchHandle bh = BranchHandle.getBranchHandle(i);
  493. InstructionList il = new InstructionList();
  494. il.append(bh);
  495. insert(ih, il);
  496. return bh;
  497. }
  498. /**
  499. * Take all instructions (handles) from "start" to "end" and append them after the new location "target". Of course, "end" must
  500. * be after "start" and target must not be located withing this range. If you want to move something to the start of the list
  501. * use null as value for target.<br>
  502. * Any instruction targeters pointing to handles within the block, keep their targets.
  503. *
  504. * @param start of moved block
  505. * @param end of moved block
  506. * @param target of moved block
  507. */
  508. public void move(InstructionHandle start, InstructionHandle end, InstructionHandle target) {
  509. // Step 1: Check constraints
  510. if (start == null || end == null) {
  511. throw new ClassGenException("Invalid null handle: From " + start + " to " + end);
  512. }
  513. if (target == start || target == end) {
  514. throw new ClassGenException("Invalid range: From " + start + " to " + end + " contains target " + target);
  515. }
  516. for (InstructionHandle ih = start; ih != end.next; ih = ih.next) {
  517. if (ih == null) {
  518. throw new ClassGenException("Invalid range: From " + start + " to " + end);
  519. } else if (ih == target) {
  520. throw new ClassGenException("Invalid range: From " + start + " to " + end + " contains target " + target);
  521. }
  522. }
  523. // Step 2: Temporarily remove the given instructions from the list
  524. InstructionHandle prev = start.prev, next = end.next;
  525. if (prev != null) {
  526. prev.next = next;
  527. } else {
  528. this.start = next;
  529. }
  530. if (next != null) {
  531. next.prev = prev;
  532. } else {
  533. this.end = prev;
  534. }
  535. start.prev = end.next = null;
  536. // Step 3: append after target
  537. if (target == null) { // append to start of list
  538. end.next = this.start;
  539. this.start = start;
  540. } else {
  541. next = target.next;
  542. target.next = start;
  543. start.prev = target;
  544. end.next = next;
  545. if (next != null) {
  546. next.prev = end;
  547. }
  548. }
  549. }
  550. /**
  551. * Move a single instruction (handle) to a new location.
  552. *
  553. * @param ih moved instruction
  554. * @param target new location of moved instruction
  555. */
  556. public void move(InstructionHandle ih, InstructionHandle target) {
  557. move(ih, ih, target);
  558. }
  559. /**
  560. * Remove from instruction 'prev' to instruction 'next' both contained in this list.
  561. *
  562. * If careAboutLostTargeters is true then this method will throw a TargetLostException when one of the removed instruction
  563. * handles is still being targeted.
  564. *
  565. * @param prev where to start deleting (predecessor, exclusive)
  566. * @param next where to end deleting (successor, exclusive)
  567. */
  568. private void remove(InstructionHandle prev, InstructionHandle next, boolean careAboutLostTargeters) throws TargetLostException {
  569. InstructionHandle first, last; // First and last deleted instruction
  570. if (prev == null && next == null) { // singleton list
  571. first = last = start;
  572. start = end = null;
  573. } else {
  574. if (prev == null) { // At start of list
  575. first = start;
  576. start = next;
  577. } else {
  578. first = prev.next;
  579. prev.next = next;
  580. }
  581. if (next == null) { // At end of list
  582. last = end;
  583. end = prev;
  584. } else {
  585. last = next.prev;
  586. next.prev = prev;
  587. }
  588. }
  589. first.prev = null; // Completely separated from rest of list
  590. last.next = null;
  591. if (!careAboutLostTargeters) {
  592. return;
  593. }
  594. List<InstructionHandle> target_vec = new ArrayList<>();
  595. for (InstructionHandle ih = first; ih != null; ih = ih.next) {
  596. ih.getInstruction().dispose(); // e.g. BranchInstructions release their targets
  597. }
  598. StringBuilder buf = new StringBuilder("{ ");
  599. for (InstructionHandle ih = first; ih != null; ih = next) {
  600. next = ih.next;
  601. length--;
  602. Set<InstructionTargeter> targeters = ih.getTargeters();
  603. boolean isOK = false;
  604. for (InstructionTargeter instructionTargeter : targeters) {
  605. if (instructionTargeter.getClass().getName().endsWith("ShadowRange")
  606. || instructionTargeter.getClass().getName().endsWith("ExceptionRange")
  607. || instructionTargeter.getClass().getName().endsWith("LineNumberTag")) {
  608. isOK = true;
  609. } else {
  610. System.out.println(instructionTargeter.getClass());
  611. }
  612. }
  613. if (!isOK) {
  614. target_vec.add(ih);
  615. buf.append(ih.toString(true) + " ");
  616. ih.next = ih.prev = null;
  617. } else {
  618. ih.dispose();
  619. }
  620. // if (ih.hasTargeters()) { // Still got targeters?
  621. // InstructionTargeter[] targeters = ih.getTargeters();
  622. // boolean isOK = false;
  623. // for (int i = 0; i < targeters.length; i++) {
  624. // InstructionTargeter instructionTargeter = targeters[i];
  625. // if (instructionTargeter.getClass().getName().endsWith("ShadowRange")
  626. // || instructionTargeter.getClass().getName().endsWith("ExceptionRange")
  627. // || instructionTargeter.getClass().getName().endsWith("LineNumberTag")) {
  628. // isOK = true;
  629. // } else {
  630. // System.out.println(instructionTargeter.getClass());
  631. // }
  632. // }
  633. // if (!isOK) {
  634. // target_vec.add(ih);
  635. // buf.append(ih.toString(true) + " ");
  636. // ih.next = ih.prev = null;
  637. // } else {
  638. // ih.dispose();
  639. // }
  640. // } else {
  641. // ih.dispose();
  642. // }
  643. }
  644. buf.append("}");
  645. if (!target_vec.isEmpty()) {
  646. InstructionHandle[] targeted = new InstructionHandle[target_vec.size()];
  647. target_vec.toArray(targeted);
  648. throw new TargetLostException(targeted, buf.toString());
  649. }
  650. }
  651. /**
  652. * Remove instruction from this list. The corresponding Instruction handles must not be reused!
  653. *
  654. * @param ih instruction (handle) to remove
  655. */
  656. public void delete(InstructionHandle ih) throws TargetLostException {
  657. remove(ih.prev, ih.next, false);
  658. }
  659. /**
  660. * Remove instruction from this list. The corresponding Instruction handles must not be reused!
  661. *
  662. * @param i instruction to remove
  663. */
  664. // public void delete(Instruction i) throws TargetLostException {
  665. // InstructionHandle ih;
  666. //
  667. // if((ih = findInstruction1(i)) == null)
  668. // throw new ClassGenException("Instruction " + i +
  669. // " is not contained in this list.");
  670. // delete(ih);
  671. // }
  672. /**
  673. * Remove instructions from instruction `from' to instruction `to' contained in this list. The user must ensure that `from' is
  674. * an instruction before `to', or risk havoc. The corresponding Instruction handles must not be reused!
  675. *
  676. * @param from where to start deleting (inclusive)
  677. * @param to where to end deleting (inclusive)
  678. */
  679. public void delete(InstructionHandle from, InstructionHandle to) throws TargetLostException {
  680. remove(from.prev, to.next, false);
  681. }
  682. /**
  683. * Remove instructions from instruction `from' to instruction `to' contained in this list. The user must ensure that `from' is
  684. * an instruction before `to', or risk havoc. The corresponding Instruction handles must not be reused!
  685. *
  686. * @param from where to start deleting (inclusive)
  687. * @param to where to end deleting (inclusive)
  688. */
  689. public void delete(Instruction from, Instruction to) throws TargetLostException {
  690. InstructionHandle from_ih, to_ih;
  691. if ((from_ih = findInstruction1(from)) == null) {
  692. throw new ClassGenException("Instruction " + from + " is not contained in this list.");
  693. }
  694. if ((to_ih = findInstruction2(to)) == null) {
  695. throw new ClassGenException("Instruction " + to + " is not contained in this list.");
  696. }
  697. delete(from_ih, to_ih);
  698. }
  699. /**
  700. * Search for given Instruction reference, start at beginning of list.
  701. *
  702. * @param i instruction to search for
  703. * @return instruction found on success, null otherwise
  704. */
  705. private InstructionHandle findInstruction1(Instruction i) {
  706. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  707. if (ih.instruction == i) {
  708. return ih;
  709. }
  710. }
  711. return null;
  712. }
  713. /**
  714. * Search for given Instruction reference, start at end of list
  715. *
  716. * @param i instruction to search for
  717. * @return instruction found on success, null otherwise
  718. */
  719. private InstructionHandle findInstruction2(Instruction i) {
  720. for (InstructionHandle ih = end; ih != null; ih = ih.prev) {
  721. if (ih.instruction == i) {
  722. return ih;
  723. }
  724. }
  725. return null;
  726. }
  727. public boolean contains(InstructionHandle i) {
  728. if (i == null) {
  729. return false;
  730. }
  731. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  732. if (ih == i) {
  733. return true;
  734. }
  735. }
  736. return false;
  737. }
  738. public boolean contains(Instruction i) {
  739. return findInstruction1(i) != null;
  740. }
  741. public void setPositions() {
  742. setPositions(false);
  743. }
  744. /**
  745. * Give all instructions their position number (offset in byte stream), i.e., make the list ready to be dumped.
  746. *
  747. * @param check Perform sanity checks, e.g. if all targeted instructions really belong to this list
  748. */
  749. public void setPositions(boolean check) {
  750. int maxAdditionalBytes = 0;
  751. int index = 0, count = 0;
  752. int[] pos = new int[length];
  753. // Pass 0: Sanity checks
  754. if (check) {
  755. checkInstructionList();
  756. }
  757. // Pass 1: Set position numbers and sum up the maximum number of bytes an
  758. // instruction may be shifted.
  759. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  760. Instruction i = ih.instruction;
  761. ih.setPosition(index);
  762. pos[count++] = index;
  763. /*
  764. * Get an estimate about how many additional bytes may be added, because BranchInstructions may have variable length
  765. * depending on the target offset (short vs. int) or alignment issues (TABLESWITCH and LOOKUPSWITCH).
  766. */
  767. switch (i.opcode) {
  768. case Constants.JSR:
  769. case Constants.GOTO:
  770. maxAdditionalBytes += 2;
  771. break;
  772. case Constants.TABLESWITCH:
  773. case Constants.LOOKUPSWITCH:
  774. maxAdditionalBytes += 3;
  775. break;
  776. }
  777. index += i.getLength();
  778. }
  779. // OPTIMIZE positions will only move around if there have been expanding instructions
  780. // if (max_additional_bytes==0...) {
  781. //
  782. // }
  783. /*
  784. * Pass 2: Expand the variable-length (Branch)Instructions depending on the target offset (short or int) and ensure that
  785. * branch targets are within this list.
  786. */
  787. boolean nonZeroOffset = false;
  788. int offset = 0;
  789. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  790. if (ih instanceof BranchHandle) {
  791. offset += ((BranchHandle) ih).updatePosition(offset, maxAdditionalBytes);
  792. if (offset != 0) {
  793. nonZeroOffset = true;
  794. }
  795. }
  796. }
  797. if (nonZeroOffset) {
  798. /*
  799. * Pass 3: Update position numbers (which may have changed due to the preceding expansions), like pass 1.
  800. */
  801. index = count = 0;
  802. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  803. Instruction i = ih.instruction;
  804. ih.setPosition(index);
  805. pos[count++] = index;
  806. index += i.getLength();
  807. }
  808. }
  809. positions = new int[count]; // Trim to proper size
  810. System.arraycopy(pos, 0, positions, 0, count);
  811. }
  812. private void checkInstructionList() {
  813. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  814. Instruction i = ih.instruction;
  815. if (i instanceof InstructionBranch) { // target instruction within list?
  816. Instruction inst = ((InstructionBranch) i).getTarget().instruction;
  817. if (!contains(inst)) {
  818. throw new ClassGenException("Branch target of " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst
  819. + " not in instruction list");
  820. }
  821. if (i instanceof InstructionSelect) {
  822. InstructionHandle[] targets = ((InstructionSelect) i).getTargets();
  823. for (InstructionHandle target : targets) {
  824. inst = target.instruction;
  825. if (!contains(inst)) {
  826. throw new ClassGenException("Branch target of " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst
  827. + " not in instruction list");
  828. }
  829. }
  830. }
  831. if (!(ih instanceof BranchHandle)) {
  832. throw new ClassGenException("Branch instruction " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst
  833. + " not contained in BranchHandle.");
  834. }
  835. }
  836. }
  837. }
  838. /**
  839. * When everything is finished, use this method to convert the instruction list into an array of bytes.
  840. *
  841. * @return the byte code ready to be dumped
  842. */
  843. public byte[] getByteCode() {
  844. // Update position indices of instructions
  845. setPositions();
  846. ByteArrayOutputStream b = new ByteArrayOutputStream();
  847. DataOutputStream out = new DataOutputStream(b);
  848. try {
  849. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  850. Instruction i = ih.instruction;
  851. i.dump(out); // Traverse list
  852. }
  853. } catch (IOException e) {
  854. System.err.println(e);
  855. return null;
  856. }
  857. byte[] byteCode = b.toByteArray();
  858. if (byteCode.length > Constants.MAX_CODE_SIZE) {
  859. throw new ClassGenException("Code size too big: " + byteCode.length);
  860. }
  861. return byteCode;
  862. }
  863. /**
  864. * @return an array of instructions without target information for branch instructions.
  865. */
  866. public Instruction[] getInstructions() {
  867. ByteSequence bytes = new ByteSequence(getByteCode());
  868. List<Instruction> instructions = new ArrayList<>();
  869. try {
  870. while (bytes.available() > 0) {
  871. instructions.add(Instruction.readInstruction(bytes));
  872. }
  873. } catch (IOException e) {
  874. throw new ClassGenException(e.toString());
  875. }
  876. Instruction[] result = new Instruction[instructions.size()];
  877. instructions.toArray(result);
  878. return result;
  879. }
  880. @Override
  881. public String toString() {
  882. return toString(true);
  883. }
  884. /**
  885. * @param verbose toggle output format
  886. * @return String containing all instructions in this list.
  887. */
  888. public String toString(boolean verbose) {
  889. StringBuilder buf = new StringBuilder();
  890. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  891. buf.append(ih.toString(verbose) + "\n");
  892. }
  893. return buf.toString();
  894. }
  895. /**
  896. * @return Enumeration that lists all instructions (handles)
  897. */
  898. public Iterator iterator() {
  899. return new Iterator() {
  900. private InstructionHandle ih = start;
  901. public Object next() {
  902. InstructionHandle i = ih;
  903. ih = ih.next;
  904. return i;
  905. }
  906. public void remove() {
  907. throw new UnsupportedOperationException();
  908. }
  909. public boolean hasNext() {
  910. return ih != null;
  911. }
  912. };
  913. }
  914. /**
  915. * @return array containing all instructions (handles)
  916. */
  917. public InstructionHandle[] getInstructionHandles() {
  918. InstructionHandle[] ihs = new InstructionHandle[length];
  919. InstructionHandle ih = start;
  920. for (int i = 0; i < length; i++) {
  921. ihs[i] = ih;
  922. ih = ih.next;
  923. }
  924. return ihs;
  925. }
  926. /**
  927. * Get positions (offsets) of all instructions in the list. This relies on that the list has been freshly created from an byte
  928. * code array, or that setPositions() has been called. Otherwise this may be inaccurate.
  929. *
  930. * @return array containing all instruction's offset in byte code
  931. */
  932. public int[] getInstructionPositions() {
  933. return positions;
  934. }
  935. /**
  936. * @return complete, i.e., deep copy of this list
  937. */
  938. public InstructionList copy() {
  939. HashMap<InstructionHandle, InstructionHandle> map = new HashMap<>();
  940. InstructionList il = new InstructionList();
  941. /*
  942. * Pass 1: Make copies of all instructions, append them to the new list and associate old instruction references with the
  943. * new ones, i.e., a 1:1 mapping.
  944. */
  945. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  946. Instruction i = ih.instruction;
  947. Instruction c = i.copy(); // Use clone for shallow copy
  948. if (c instanceof InstructionBranch) {
  949. map.put(ih, il.append((InstructionBranch) c));
  950. } else {
  951. map.put(ih, il.append(c));
  952. }
  953. }
  954. /*
  955. * Pass 2: Update branch targets.
  956. */
  957. InstructionHandle ih = start;
  958. InstructionHandle ch = il.start;
  959. while (ih != null) {
  960. Instruction i = ih.instruction;
  961. Instruction c = ch.instruction;
  962. if (i instanceof InstructionBranch) {
  963. InstructionBranch bi = (InstructionBranch) i;
  964. InstructionBranch bc = (InstructionBranch) c;
  965. InstructionHandle itarget = bi.getTarget(); // old target
  966. // New target is in hash map
  967. bc.setTarget(map.get(itarget));
  968. if (bi instanceof InstructionSelect) { // Either LOOKUPSWITCH or TABLESWITCH
  969. InstructionHandle[] itargets = ((InstructionSelect) bi).getTargets();
  970. InstructionHandle[] ctargets = ((InstructionSelect) bc).getTargets();
  971. for (int j = 0; j < itargets.length; j++) { // Update all targets
  972. ctargets[j] = map.get(itargets[j]);
  973. }
  974. }
  975. }
  976. ih = ih.next;
  977. ch = ch.next;
  978. }
  979. return il;
  980. }
  981. /**
  982. * Replace all references to the old constant pool with references to the new constant pool
  983. */
  984. public void replaceConstantPool(ConstantPool old_cp, ConstantPool new_cp) {
  985. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  986. Instruction i = ih.instruction;
  987. if (i.isConstantPoolInstruction()) {
  988. InstructionCP ci = (InstructionCP) i;
  989. Constant c = old_cp.getConstant(ci.getIndex());
  990. ci.setIndex(new_cp.addConstant(c, old_cp));
  991. }
  992. }
  993. }
  994. private void clear() {
  995. start = end = null;
  996. length = 0;
  997. }
  998. /**
  999. * Delete contents of list. Provides better memory utilization, because the system then may reuse the instruction handles. This
  1000. * method is typically called right after <href="MethodGen.html#getMethod()">MethodGen.getMethod()</a>.
  1001. */
  1002. public void dispose() {
  1003. // Traverse in reverse order, because ih.next is overwritten
  1004. for (InstructionHandle ih = end; ih != null; ih = ih.prev) {
  1005. /*
  1006. * Causes BranchInstructions to release target and targeters, because it calls dispose() on the contained instruction.
  1007. */
  1008. ih.dispose();
  1009. }
  1010. clear();
  1011. }
  1012. /**
  1013. * @return start of list
  1014. */
  1015. public InstructionHandle getStart() {
  1016. return start;
  1017. }
  1018. /**
  1019. * @return end of list
  1020. */
  1021. public InstructionHandle getEnd() {
  1022. return end;
  1023. }
  1024. /**
  1025. * @return length of list (Number of instructions, not bytes)
  1026. */
  1027. public int getLength() {
  1028. return length;
  1029. }
  1030. /**
  1031. * @return length of list (Number of instructions, not bytes)
  1032. */
  1033. public int size() {
  1034. return length;
  1035. }
  1036. /**
  1037. * Redirect all references from old_target to new_target, i.e., update targets of branch instructions.
  1038. *
  1039. * @param old_target the old target instruction handle
  1040. * @param new_target the new target instruction handle
  1041. */
  1042. public void redirectBranches(InstructionHandle old_target, InstructionHandle new_target) {
  1043. for (InstructionHandle ih = start; ih != null; ih = ih.next) {
  1044. Instruction i = ih.getInstruction();
  1045. if (i instanceof InstructionBranch) {
  1046. InstructionBranch b = (InstructionBranch) i;
  1047. InstructionHandle target = b.getTarget();
  1048. if (target == old_target) {
  1049. b.setTarget(new_target);
  1050. }
  1051. if (b instanceof InstructionSelect) { // Either LOOKUPSWITCH or TABLESWITCH
  1052. InstructionHandle[] targets = ((InstructionSelect) b).getTargets();
  1053. for (int j = 0; j < targets.length; j++) {
  1054. if (targets[j] == old_target) {
  1055. ((InstructionSelect) b).setTarget(j, new_target);
  1056. }
  1057. }
  1058. }
  1059. }
  1060. }
  1061. }
  1062. /**
  1063. * Redirect all references of local variables from old_target to new_target.
  1064. *
  1065. * @param lg array of local variables
  1066. * @param old_target the old target instruction handle
  1067. * @param new_target the new target instruction handle
  1068. * @see MethodGen
  1069. */
  1070. public void redirectLocalVariables(LocalVariableGen[] lg, InstructionHandle old_target, InstructionHandle new_target) {
  1071. for (LocalVariableGen localVariableGen : lg) {
  1072. InstructionHandle start = localVariableGen.getStart();
  1073. InstructionHandle end = localVariableGen.getEnd();
  1074. if (start == old_target) {
  1075. localVariableGen.setStart(new_target);
  1076. }
  1077. if (end == old_target) {
  1078. localVariableGen.setEnd(new_target);
  1079. }
  1080. }
  1081. }
  1082. /**
  1083. * Redirect all references of exception handlers from old_target to new_target.
  1084. *
  1085. * @param exceptions array of exception handlers
  1086. * @param old_target the old target instruction handle
  1087. * @param new_target the new target instruction handle
  1088. * @see MethodGen
  1089. */
  1090. public void redirectExceptionHandlers(CodeExceptionGen[] exceptions, InstructionHandle old_target, InstructionHandle new_target) {
  1091. for (CodeExceptionGen exception : exceptions) {
  1092. if (exception.getStartPC() == old_target) {
  1093. exception.setStartPC(new_target);
  1094. }
  1095. if (exception.getEndPC() == old_target) {
  1096. exception.setEndPC(new_target);
  1097. }
  1098. if (exception.getHandlerPC() == old_target) {
  1099. exception.setHandlerPC(new_target);
  1100. }
  1101. }
  1102. }
  1103. }