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.Constants;
62 import com.sun.org.apache.bcel.internal.classfile.*;
63 import java.util.Objects;
64 
65 /**
66  * This class represents a local variable within a method. It contains its
67  * scope, name and type. The generated LocalVariable object can be obtained
68  * with getLocalVariable which needs the instruction list and the constant
69  * pool as parameters.
70  *
71  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
72  * @see     LocalVariable
73  * @see     MethodGen
74  */
75 public class LocalVariableGen
76   implements InstructionTargeter, NamedAndTyped, Cloneable,
77              java.io.Serializable
78 {
79   private final int   index;
80   private String      name;
81   private Type        type;
82   private InstructionHandle start, end;
83 
84   /**
85    * Generate a local variable that with index `index'. Note that double and long
86    * variables need two indexs. Index indices have to be provided by the user.
87    *
88    * @param index index of local variable
89    * @param name its name
90    * @param type its type
91    * @param start from where the instruction is valid (null means from the start)
92    * @param end until where the instruction is valid (null means to the end)
93    */
LocalVariableGen(int index, String name, Type type, InstructionHandle start, InstructionHandle end)94   public LocalVariableGen(int index, String name, Type type,
95                           InstructionHandle start, InstructionHandle end) {
96     if((index < 0) || (index > Constants.MAX_SHORT))
97       throw new ClassGenException("Invalid index index: " + index);
98 
99     this.name  = name;
100     this.type  = type;
101     this.index  = index;
102     setStart(start);
103     setEnd(end);
104   }
105 
106   /**
107    * Get LocalVariable object.
108    *
109    * This relies on that the instruction list has already been dumped to byte code or
110    * or that the `setPositions' methods has been called for the instruction list.
111    *
112    * Note that for local variables whose scope end at the last
113    * instruction of the method's code, the JVM specification is ambiguous:
114    * both a start_pc+length ending at the last instruction and
115    * start_pc+length ending at first index beyond the end of the code are
116    * valid.
117    *
118    * @param il instruction list (byte code) which this variable belongs to
119    * @param cp constant pool
120    */
getLocalVariable(ConstantPoolGen cp)121   public LocalVariable getLocalVariable(ConstantPoolGen cp) {
122     int start_pc        = start.getPosition();
123     int length          = end.getPosition() - start_pc;
124 
125     if(length > 0)
126       length += end.getInstruction().getLength();
127 
128     int name_index      = cp.addUtf8(name);
129     int signature_index = cp.addUtf8(type.getSignature());
130 
131     return new LocalVariable(start_pc, length, name_index,
132                              signature_index, index, cp.getConstantPool());
133   }
134 
getIndex()135   public int         getIndex()                  { return index; }
136   @Override
setName(String name)137   public void        setName(String name)        { this.name = name; }
138   @Override
getName()139   public String      getName()                   { return name; }
140   @Override
setType(Type type)141   public void        setType(Type type)          { this.type = type; }
142   @Override
getType()143   public Type        getType()                   { return type; }
144 
getStart()145   public InstructionHandle getStart()                  { return start; }
getEnd()146   public InstructionHandle getEnd()                    { return end; }
147 
148   /**
149    * Remove this from any known HashSet in which it might be registered.
150    */
notifyTargetChanging()151   void notifyTargetChanging() {
152     // hashCode depends on 'index', 'start', and 'end'.
153     // Therefore before changing any of these values we
154     // need to unregister 'this' from any HashSet where
155     // this is registered, and then we need to add it
156     // back...
157 
158     // Unregister 'this' from the HashSet held by 'start'.
159     BranchInstruction.notifyTargetChanging(this.start, this);
160     if (this.end != this.start) {
161         // Since hashCode() is going to change we need to unregister
162         // 'this' both form 'start' and 'end'.
163         // Unregister 'this' from the HashSet held by 'end'.
164         BranchInstruction.notifyTargetChanging(this.end, this);
165     }
166   }
167 
168   /**
169    * Add back 'this' in all HashSet in which it should be registered.
170    **/
notifyTargetChanged()171   void notifyTargetChanged() {
172     // hashCode depends on 'index', 'start', and 'end'.
173     // Therefore before changing any of these values we
174     // need to unregister 'this' from any HashSet where
175     // this is registered, and then we need to add it
176     // back...
177 
178     // Register 'this' in the HashSet held by start.
179     BranchInstruction.notifyTargetChanged(this.start, this);
180     if (this.end != this.start) {
181         // Since hashCode() has changed we need to register
182         // 'this' again in 'end'.
183         // Add back 'this' in the HashSet held by 'end'.
184         BranchInstruction.notifyTargetChanged(this.end, this);
185     }
186   }
187 
setStart(InstructionHandle start)188   public final void setStart(InstructionHandle start) {
189 
190     // Call notifyTargetChanging *before* modifying this,
191     // as the code triggered by notifyTargetChanging
192     // depends on this pointing to the 'old' start.
193     notifyTargetChanging();
194 
195     this.start = start;
196 
197     // call notifyTargetChanged *after* modifying this,
198     // as the code triggered by notifyTargetChanged
199     // depends on this pointing to the 'new' start.
200     notifyTargetChanged();
201   }
202 
setEnd(InstructionHandle end)203   public final void setEnd(InstructionHandle end) {
204     // call notifyTargetChanging *before* modifying this,
205     // as the code triggered by notifyTargetChanging
206     // depends on this pointing to the 'old' end.
207     // Unregister 'this' from the HashSet held by the 'old' end.
208     notifyTargetChanging();
209 
210     this.end = end;
211 
212     // call notifyTargetChanged *after* modifying this,
213     // as the code triggered by notifyTargetChanged
214     // depends on this pointing to the 'new' end.
215     // Register 'this' in the HashSet held by the 'new' end.
216     notifyTargetChanged();
217 
218   }
219 
220   /**
221    * @param old_ih old target, either start or end
222    * @param new_ih new target
223    */
224   @Override
updateTarget(InstructionHandle old_ih, InstructionHandle new_ih)225   public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) {
226     boolean targeted = false;
227 
228     if(start == old_ih) {
229       targeted = true;
230       setStart(new_ih);
231     }
232 
233     if(end == old_ih) {
234       targeted = true;
235       setEnd(new_ih);
236     }
237 
238     if(!targeted)
239       throw new ClassGenException("Not targeting " + old_ih + ", but {" + start + ", " +
240                                   end + "}");
241   }
242 
243   /**
244    * @return true, if ih is target of this variable
245    */
246   @Override
containsTarget(InstructionHandle ih)247   public boolean containsTarget(InstructionHandle ih) {
248     return (start == ih) || (end == ih);
249   }
250 
251   /**
252    * We consider two local variables to be equal, if they use the same index and
253    * are valid in the same range.
254    */
255   @Override
equals(Object o)256   public boolean equals(Object o) {
257     if (o==this)
258       return true;
259 
260     if(!(o instanceof LocalVariableGen))
261       return false;
262 
263     LocalVariableGen l = (LocalVariableGen)o;
264     return (l.index == index) && (l.start == start) && (l.end == end);
265   }
266 
267   @Override
hashCode()268   public int hashCode() {
269     int hash = 7;
270     hash = 59 * hash + this.index;
271     hash = 59 * hash + Objects.hashCode(this.start);
272     hash = 59 * hash + Objects.hashCode(this.end);
273     return hash;
274   }
275 
276   @Override
toString()277   public String toString() {
278     return "LocalVariableGen(" + name +  ", " + type +  ", " + start + ", " + end + ")";
279   }
280 
281   @Override
clone()282   public Object clone() {
283     try {
284       return super.clone();
285     } catch(CloneNotSupportedException e) {
286       System.err.println(e);
287       return null;
288     }
289   }
290 }
291