001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 */
018 package org.apache.bcel.generic;
019
020 import org.apache.bcel.Constants;
021 import org.apache.bcel.classfile.LocalVariable;
022
023 /**
024 * This class represents a local variable within a method. It contains its
025 * scope, name and type. The generated LocalVariable object can be obtained
026 * with getLocalVariable which needs the instruction list and the constant
027 * pool as parameters.
028 *
029 * @version $Id: LocalVariableGen.java 1152072 2011-07-29 01:54:05Z dbrosius $
030 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
031 * @see LocalVariable
032 * @see MethodGen
033 */
034 public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable,
035 java.io.Serializable {
036
037 private static final long serialVersionUID = -3810966319065955534L;
038 private int index;
039 private String name;
040 private Type type;
041 private InstructionHandle start, end;
042
043
044 /**
045 * Generate a local variable that with index `index'. Note that double and long
046 * variables need two indexs. Index indices have to be provided by the user.
047 *
048 * @param index index of local variable
049 * @param name its name
050 * @param type its type
051 * @param start from where the instruction is valid (null means from the start)
052 * @param end until where the instruction is valid (null means to the end)
053 */
054 public LocalVariableGen(int index, String name, Type type, InstructionHandle start,
055 InstructionHandle end) {
056 if ((index < 0) || (index > Constants.MAX_SHORT)) {
057 throw new ClassGenException("Invalid index index: " + index);
058 }
059 this.name = name;
060 this.type = type;
061 this.index = index;
062 setStart(start);
063 setEnd(end);
064 }
065
066
067 /**
068 * Get LocalVariable object.
069 *
070 * This relies on that the instruction list has already been dumped to byte code or
071 * or that the `setPositions' methods has been called for the instruction list.
072 *
073 * Note that for local variables whose scope end at the last
074 * instruction of the method's code, the JVM specification is ambiguous:
075 * both a start_pc+length ending at the last instruction and
076 * start_pc+length ending at first index beyond the end of the code are
077 * valid.
078 *
079 * @param cp constant pool
080 */
081 public LocalVariable getLocalVariable( ConstantPoolGen cp ) {
082 int start_pc = start.getPosition();
083 int length = end.getPosition() - start_pc;
084 if (length > 0) {
085 length += end.getInstruction().getLength();
086 }
087 int name_index = cp.addUtf8(name);
088 int signature_index = cp.addUtf8(type.getSignature());
089 return new LocalVariable(start_pc, length, name_index, signature_index, index, cp
090 .getConstantPool());
091 }
092
093
094 public void setIndex( int index ) {
095 this.index = index;
096 }
097
098
099 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 }