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.Constants;
21 import org.apache.bcel.classfile.LocalVariable;
22
23 /**
24 * This class 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 * @version $Id: LocalVariableGen.java 1152072 2011-07-29 01:54:05Z dbrosius $
30 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
31 * @see LocalVariable
32 * @see MethodGen
33 */
34 public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable,
35 java.io.Serializable {
36
37 private static final long serialVersionUID = -3810966319065955534L;
38 private int index;
39 private String name;
40 private Type type;
41 private InstructionHandle start, end;
42
43
44 /**
45 * Generate a local variable that with index `index'. Note that double and long
46 * variables need two indexs. Index indices have to be provided by the user.
47 *
48 * @param index index of local variable
49 * @param name its name
50 * @param type its type
51 * @param start from where the instruction is valid (null means from the start)
52 * @param end until where the instruction is valid (null means to the end)
53 */
54 public LocalVariableGen(int index, String name, Type type, InstructionHandle start,
55 InstructionHandle end) {
56 if ((index < 0) || (index > Constants.MAX_SHORT)) {
57 throw new ClassGenException("Invalid index index: " + index);
58 }
59 this.name = name;
60 this.type = type;
61 this.index = index;
62 setStart(start);
63 setEnd(end);
64 }
65
66
67 /**
68 * Get LocalVariable object.
69 *
70 * This relies on that the instruction list has already been dumped to byte code or
71 * or that the `setPositions' methods has been called for the instruction list.
72 *
73 * Note that for local variables whose scope end at the last
74 * instruction of the method's code, the JVM specification is ambiguous:
75 * both a start_pc+length ending at the last instruction and
76 * start_pc+length ending at first index beyond the end of the code are
77 * valid.
78 *
79 * @param cp constant pool
80 */
81 public LocalVariable getLocalVariable( ConstantPoolGen cp ) {
82 int start_pc = start.getPosition();
83 int length = end.getPosition() - start_pc;
84 if (length > 0) {
85 length += end.getInstruction().getLength();
86 }
87 int name_index = cp.addUtf8(name);
88 int signature_index = cp.addUtf8(type.getSignature());
89 return new LocalVariable(start_pc, length, name_index, signature_index, index, cp
90 .getConstantPool());
91 }
92
93
94 public void setIndex( int index ) {
95 this.index = index;
96 }
97
98
99 public int getIndex() {
100 return index;
101 }
102
103
104 public void setName( String name ) {
105 this.name = name;
106 }
107
108
109 public String getName() {
110 return name;
111 }
112
113
114 public void setType( Type type ) {
115 this.type = type;
116 }
117
118
119 public Type getType() {
120 return type;
121 }
122
123
124 public InstructionHandle getStart() {
125 return start;
126 }
127
128
129 public InstructionHandle getEnd() {
130 return end;
131 }
132
133
134 public void setStart( InstructionHandle start ) {
135 BranchInstruction.notifyTarget(this.start, start, this);
136 this.start = start;
137 }
138
139
140 public void setEnd( InstructionHandle end ) {
141 BranchInstruction.notifyTarget(this.end, end, this);
142 this.end = end;
143 }
144
145
146 /**
147 * @param old_ih old target, either start or end
148 * @param new_ih new target
149 */
150 public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) {
151 boolean targeted = false;
152 if (start == old_ih) {
153 targeted = true;
154 setStart(new_ih);
155 }
156 if (end == old_ih) {
157 targeted = true;
158 setEnd(new_ih);
159 }
160 if (!targeted) {
161 throw new ClassGenException("Not targeting " + old_ih + ", but {" + start + ", " + end
162 + "}");
163 }
164 }
165
166
167 /**
168 * @return true, if ih is target of this variable
169 */
170 public boolean containsTarget( InstructionHandle ih ) {
171 return (start == ih) || (end == ih);
172 }
173
174
175 /** @return a hash code value for the object.
176 */
177 @Override
178 public int hashCode() {
179 //If the user changes the name or type, problems with the targeter hashmap will occur
180 int hc = index ^ name.hashCode() ^ type.hashCode();
181 return hc;
182 }
183
184
185 /**
186 * We consider to local variables to be equal, if the use the same index and
187 * are valid in the same range.
188 */
189 @Override
190 public boolean equals( Object o ) {
191 if (!(o instanceof LocalVariableGen)) {
192 return false;
193 }
194 LocalVariableGen l = (LocalVariableGen) o;
195 return (l.index == index) && (l.start == start) && (l.end == end);
196 }
197
198
199 @Override
200 public String toString() {
201 return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")";
202 }
203
204
205 @Override
206 public Object clone() {
207 try {
208 return super.clone();
209 } catch (CloneNotSupportedException e) {
210 System.err.println(e);
211 return null;
212 }
213 }
214 }