View Javadoc
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  
90    public final InstructionHandle getNext()        { return next; }
91    public final InstructionHandle getPrev()        { return prev; }
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     */
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    */
116   public Instruction swapInstruction(Instruction i) {
117     Instruction oldInstruction = instruction;
118     instruction = i;
119     return oldInstruction;
120   }
121 
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    */
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    */
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    */
162   public int getPosition() { return i_position; }
163 
164   /** Set the position, i.e., the byte code offset of the contained
165    * instruction.
166    */
167   void setPosition(int pos) { i_position = pos; }
168 
169   /** Overridden in BranchHandle
170    */
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    */
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    */
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    */
199   public void removeTargeter(InstructionTargeter t) {
200     targeters.remove(t);
201   }
202 
203   /**
204    * Denote this handle is being referenced by t.
205    */
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 
214   public boolean hasTargeters() {
215     return (targeters != null) && (targeters.size() > 0);
216   }
217 
218   /**
219    * @return null, if there are no targeters
220    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
284   public void accept(Visitor v) {
285     instruction.accept(v);
286   }
287 }