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