View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   *
17   */
18  package org.apache.bcel.generic;
19  
20  import org.apache.bcel.Const;
21  import org.apache.bcel.classfile.LocalVariable;
22  
23  /**
24   * Represents a local variable within a method. It contains its
25   * scope, name and type. The generated LocalVariable object can be obtained
26   * with getLocalVariable which needs the instruction list and the constant
27   * pool as parameters.
28   *
29   * @see     LocalVariable
30   * @see     MethodGen
31   */
32  public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable {
33  
34      private int index;
35      private String name;
36      private Type type;
37      private InstructionHandle start;
38      private InstructionHandle end;
39      private int origIndex; // never changes; used to match up with LocalVariableTypeTable entries
40      private boolean liveToEnd;
41  
42  
43      /**
44       * Generate a local variable that with index `index'. Note that double and long
45       * variables need two indexs. Index indices have to be provided by the user.
46       *
47       * @param index index of local variable
48       * @param name its name
49       * @param type its type
50       * @param start from where the instruction is valid (null means from the start)
51       * @param end until where the instruction is valid (null means to the end)
52       */
53      public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start,
54              final InstructionHandle end) {
55          if ((index < 0) || (index > Const.MAX_SHORT)) {
56              throw new ClassGenException("Invalid index index: " + index);
57          }
58          this.name = name;
59          this.type = type;
60          this.index = index;
61          setStart(start);
62          setEnd(end);
63          this.origIndex = index;
64          this.liveToEnd = end == null;
65      }
66  
67  
68      /**
69       * Generates a local variable that with index `index'. Note that double and long
70       * variables need two indexs. Index indices have to be provided by the user.
71       *
72       * @param index index of local variable
73       * @param name its name
74       * @param type its type
75       * @param start from where the instruction is valid (null means from the start)
76       * @param end until where the instruction is valid (null means to the end)
77       * @param origIndex index of local variable prior to any changes to index
78       */
79      public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start,
80              final InstructionHandle end, final int origIndex) {
81          this(index, name, type, start, end);
82          this.origIndex = origIndex;
83      }
84  
85  
86      /**
87       * Gets LocalVariable object.
88       *
89       * This relies on that the instruction list has already been dumped to byte code or
90       * or that the `setPositions' methods has been called for the instruction list.
91       *
92       * Note that due to the conversion from byte code offset to InstructionHandle,
93       * it is impossible to tell the difference between a live range that ends BEFORE
94       * the last insturction of the method or a live range that ends AFTER the last
95       * instruction of the method.  Hence the liveToEnd flag to differentiate
96       * between these two cases.
97       *
98       * @param cp constant pool
99       */
100     public LocalVariable getLocalVariable( final ConstantPoolGen cp ) {
101         int start_pc = 0;
102         int length = 0;
103         if ((start != null) && (end != null)) {
104             start_pc = start.getPosition();
105             length = end.getPosition() - start_pc;
106             if ((end.getNext() == null) && liveToEnd) {
107                 length += end.getInstruction().getLength();
108             }
109         }
110         final int name_index = cp.addUtf8(name);
111         final int signature_index = cp.addUtf8(type.getSignature());
112         return new LocalVariable(start_pc, length, name_index, signature_index, index, cp
113                 .getConstantPool(), origIndex);
114     }
115 
116 
117     public void setIndex( final int index ) {
118         this.index = index;
119     }
120 
121 
122     public int getIndex() {
123         return index;
124     }
125 
126 
127     public int getOrigIndex() {
128         return origIndex;
129     }
130 
131 
132     public void setLiveToEnd( final boolean live_to_end) {
133         this.liveToEnd = live_to_end;
134     }
135 
136 
137     public boolean getLiveToEnd() {
138         return liveToEnd;
139     }
140 
141 
142     @Override
143     public void setName( final String name ) {
144         this.name = name;
145     }
146 
147 
148     @Override
149     public String getName() {
150         return name;
151     }
152 
153 
154     @Override
155     public void setType( final Type type ) {
156         this.type = type;
157     }
158 
159 
160     @Override
161     public Type getType() {
162         return type;
163     }
164 
165 
166     public InstructionHandle getStart() {
167         return start;
168     }
169 
170 
171     public InstructionHandle getEnd() {
172         return end;
173     }
174 
175 
176     public void setStart( final InstructionHandle start ) { // TODO could be package-protected?
177         BranchInstruction.notifyTarget(this.start, start, this);
178         this.start = start;
179     }
180 
181 
182     public void setEnd( final InstructionHandle end ) { // TODO could be package-protected?
183         BranchInstruction.notifyTarget(this.end, end, this);
184         this.end = end;
185     }
186 
187 
188     /**
189      * @param old_ih old target, either start or end
190      * @param new_ih new target
191      */
192     @Override
193     public void updateTarget( final InstructionHandlee.html#InstructionHandle">InstructionHandle old_ih, final InstructionHandle new_ih ) {
194         boolean targeted = false;
195         if (start == old_ih) {
196             targeted = true;
197             setStart(new_ih);
198         }
199         if (end == old_ih) {
200             targeted = true;
201             setEnd(new_ih);
202         }
203         if (!targeted) {
204             throw new ClassGenException("Not targeting " + old_ih + ", but {" + start + ", " + end
205                     + "}");
206         }
207     }
208 
209     /**
210      * Clear the references from and to this variable when it's removed.
211      */
212     void dispose() {
213         setStart(null);
214         setEnd(null);
215     }
216 
217     /**
218      * @return true, if ih is target of this variable
219      */
220     @Override
221     public boolean containsTarget( final InstructionHandle ih ) {
222         return (start == ih) || (end == ih);
223     }
224 
225 
226     @Override
227     public int hashCode() {
228         // If the user changes the name or type, problems with the targeter hashmap will occur.
229         // Note: index cannot be part of hash as it may be changed by the user.
230         return name.hashCode() ^ type.hashCode();
231     }
232 
233 
234     /**
235      * We consider to local variables to be equal, if the use the same index and
236      * are valid in the same range.
237      */
238     @Override
239     public boolean equals( final Object o ) {
240         if (!(o instanceof LocalVariableGen)) {
241             return false;
242         }
243         final LocalVariableGen/../../org/apache/bcel/generic/LocalVariableGen.html#LocalVariableGen">LocalVariableGen l = (LocalVariableGen) o;
244         return (l.index == index) && (l.start == start) && (l.end == end);
245     }
246 
247 
248     @Override
249     public String toString() {
250         return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")";
251     }
252 
253 
254     @Override
255     public Object clone() {
256         try {
257             return super.clone();
258         } catch (final CloneNotSupportedException e) {
259             throw new Error("Clone Not Supported"); // never happens
260         }
261     }
262 }