1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 package com.sun.org.apache.bcel.internal.generic;
6 
7 /* ====================================================================
8  * The Apache Software License, Version 1.1
9  *
10  * Copyright (c) 2001 The Apache Software Foundation.  All rights
11  * reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  *
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  *
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in
22  *    the documentation and/or other materials provided with the
23  *    distribution.
24  *
25  * 3. The end-user documentation included with the redistribution,
26  *    if any, must include the following acknowledgment:
27  *       "This product includes software developed by the
28  *        Apache Software Foundation (http://www.apache.org/)."
29  *    Alternately, this acknowledgment may appear in the software itself,
30  *    if and wherever such third-party acknowledgments normally appear.
31  *
32  * 4. The names "Apache" and "Apache Software Foundation" and
33  *    "Apache BCEL" must not be used to endorse or promote products
34  *    derived from this software without prior written permission. For
35  *    written permission, please contact apache@apache.org.
36  *
37  * 5. Products derived from this software may not be called "Apache",
38  *    "Apache BCEL", nor may "Apache" appear in their name, without
39  *    prior written permission of the Apache Software Foundation.
40  *
41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52  * SUCH DAMAGE.
53  * ====================================================================
54  *
55  * This software consists of voluntary contributions made by many
56  * individuals on behalf of the Apache Software Foundation.  For more
57  * information on the Apache Software Foundation, please see
58  * <http://www.apache.org/>.
59  */
60 
61 import com.sun.org.apache.bcel.internal.classfile.Utility;
62 import java.util.HashSet;
63 import java.util.Collection;
64 import java.util.HashMap;
65 
66 /**
67  * Instances of this class give users a handle to the instructions contained in
68  * an InstructionList. Instruction objects may be used more than once within a
69  * list, this is useful because it saves memory and may be much faster.
70  *
71  * Within an InstructionList an InstructionHandle object is wrapped
72  * around all instructions, i.e., it implements a cell in a
73  * doubly-linked list. From the outside only the next and the
74  * previous instruction (handle) are accessible. One
75  * can traverse the list via an Enumeration returned by
76  * InstructionList.elements().
77  *
78  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
79  * @see Instruction
80  * @see BranchHandle
81  * @see InstructionList
82  */
83 public class InstructionHandle implements java.io.Serializable {
84   InstructionHandle next, prev;  // Will be set from the outside
85   Instruction       instruction;
86   protected int     i_position = -1; // byte code offset of instruction
87   private HashSet   targeters;
88   private HashMap   attributes;
89 
getNext()90   public final InstructionHandle getNext()        { return next; }
getPrev()91   public final InstructionHandle getPrev()        { return prev; }
getInstruction()92   public final Instruction       getInstruction() { return instruction; }
93 
94   /**
95    * Replace current instruction contained in this handle.
96    * Old instruction is disposed using Instruction.dispose().
97    */
setInstruction(Instruction i)98   public void setInstruction(Instruction i) { // Overridden in BranchHandle
99     if(i == null)
100       throw new ClassGenException("Assigning null to handle");
101 
102     if((this.getClass() != BranchHandle.class) && (i instanceof BranchInstruction))
103       throw new ClassGenException("Assigning branch instruction " + i + " to plain handle");
104 
105     if(instruction != null)
106       instruction.dispose();
107 
108     instruction = i;
109   }
110 
111   /**
112    * Temporarily swap the current instruction, without disturbing
113    * anything. Meant to be used by a debugger, implementing
114    * breakpoints. Current instruction is returned.
115    */
swapInstruction(Instruction i)116   public Instruction swapInstruction(Instruction i) {
117     Instruction oldInstruction = instruction;
118     instruction = i;
119     return oldInstruction;
120   }
121 
InstructionHandle(Instruction i)122   /*private*/ protected InstructionHandle(Instruction i) {
123     setInstruction(i);
124   }
125 
126   private static InstructionHandle ih_list = null; // List of reusable handles
127 
128   /** Factory method.
129    */
getInstructionHandle(Instruction i)130   static final InstructionHandle getInstructionHandle(Instruction i) {
131     if(ih_list == null)
132       return new InstructionHandle(i);
133     else {
134       InstructionHandle ih = ih_list;
135       ih_list = ih.next;
136 
137       ih.setInstruction(i);
138 
139       return ih;
140     }
141   }
142 
143   /**
144    * Called by InstructionList.setPositions when setting the position for every
145    * instruction. In the presence of variable length instructions `setPositions()'
146    * performs multiple passes over the instruction list to calculate the
147    * correct (byte) positions and offsets by calling this function.
148    *
149    * @param offset additional offset caused by preceding (variable length) instructions
150    * @param max_offset the maximum offset that may be caused by these instructions
151    * @return additional offset caused by possible change of this instruction's length
152    */
updatePosition(int offset, int max_offset)153   protected int updatePosition(int offset, int max_offset) {
154     i_position += offset;
155     return 0;
156   }
157 
158   /** @return the position, i.e., the byte code offset of the contained
159    * instruction. This is accurate only after
160    * InstructionList.setPositions() has been called.
161    */
getPosition()162   public int getPosition() { return i_position; }
163 
164   /** Set the position, i.e., the byte code offset of the contained
165    * instruction.
166    */
setPosition(int pos)167   void setPosition(int pos) { i_position = pos; }
168 
169   /** Overridden in BranchHandle
170    */
addHandle()171   protected void addHandle() {
172     next    = ih_list;
173     ih_list = this;
174   }
175 
176   /**
177    * Delete contents, i.e., remove user access and make handle reusable.
178    */
dispose()179   void dispose() {
180     next = prev = null;
181     instruction.dispose();
182     instruction = null;
183     i_position = -1;
184     attributes = null;
185     removeAllTargeters();
186     addHandle();
187   }
188 
189   /** Remove all targeters, if any.
190    */
removeAllTargeters()191   public void removeAllTargeters() {
192     if(targeters != null)
193       targeters.clear();
194   }
195 
196   /**
197    * Denote this handle isn't referenced anymore by t.
198    */
removeTargeter(InstructionTargeter t)199   public void removeTargeter(InstructionTargeter t) {
200     targeters.remove(t);
201   }
202 
203   /**
204    * Denote this handle is being referenced by t.
205    */
addTargeter(InstructionTargeter t)206   public void addTargeter(InstructionTargeter t) {
207     if(targeters == null)
208       targeters = new HashSet();
209 
210     //if(!targeters.contains(t))
211     targeters.add(t);
212   }
213 
hasTargeters()214   public boolean hasTargeters() {
215     return (targeters != null) && (targeters.size() > 0);
216   }
217 
218   /**
219    * @return null, if there are no targeters
220    */
getTargeters()221   public InstructionTargeter[] getTargeters() {
222     if(!hasTargeters())
223       return null;
224 
225     InstructionTargeter[] t = new InstructionTargeter[targeters.size()];
226     targeters.toArray(t);
227     return t;
228   }
229 
230   /** @return a (verbose) string representation of the contained instruction.
231    */
toString(boolean verbose)232   public String toString(boolean verbose) {
233     return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose);
234   }
235 
236   /** @return a string representation of the contained instruction.
237    */
toString()238   public String toString() {
239     return toString(true);
240   }
241 
242   /** Add an attribute to an instruction handle.
243    *
244    * @param key the key object to store/retrieve the attribute
245    * @param attr the attribute to associate with this handle
246    */
addAttribute(Object key, Object attr)247   public void addAttribute(Object key, Object attr) {
248     if(attributes == null)
249       attributes = new HashMap(3);
250 
251     attributes.put(key, attr);
252   }
253 
254   /** Delete an attribute of an instruction handle.
255    *
256    * @param key the key object to retrieve the attribute
257    */
removeAttribute(Object key)258   public void removeAttribute(Object key) {
259     if(attributes != null)
260       attributes.remove(key);
261   }
262 
263   /** Get attribute of an instruction handle.
264    *
265    * @param key the key object to store/retrieve the attribute
266    */
getAttribute(Object key)267   public Object getAttribute(Object key) {
268     if(attributes != null)
269       return attributes.get(key);
270 
271     return null;
272   }
273 
274   /** @return all attributes associated with this handle
275    */
getAttributes()276   public Collection getAttributes() {
277     return attributes.values();
278   }
279 
280   /** Convenience method, simply calls accept() on the contained instruction.
281    *
282    * @param v Visitor object
283    */
accept(Visitor v)284   public void accept(Visitor v) {
285     instruction.accept(v);
286   }
287 }
288