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