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

3 years ago
12 years ago
13 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
12 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
13 years ago
14 years ago
13 years ago
14 years ago
14 years ago
13 years ago
14 years ago
13 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
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. }