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 * 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$ 30 * @see LocalVariable 31 * @see MethodGen 32 */ 33 public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable { 34 35 private int index; 36 private String name; 37 private Type type; 38 private InstructionHandle start; 39 private InstructionHandle end; 40 private int orig_index; // never changes; used to match up with LocalVariableTypeTable entries 41 private boolean live_to_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 */ LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, final InstructionHandle end)54 public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, 55 final InstructionHandle end) { 56 if ((index < 0) || (index > Const.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 this.orig_index = index; 65 this.live_to_end = end == null; 66 } 67 68 69 /** 70 * Generate a local variable that with index `index'. Note that double and long 71 * variables need two indexs. Index indices have to be provided by the user. 72 * 73 * @param index index of local variable 74 * @param name its name 75 * @param type its type 76 * @param start from where the instruction is valid (null means from the start) 77 * @param end until where the instruction is valid (null means to the end) 78 * @param orig_index index of local variable prior to any changes to index 79 */ LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, final InstructionHandle end, final int orig_index)80 public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, 81 final InstructionHandle end, final int orig_index) { 82 this(index, name, type, start, end); 83 this.orig_index = orig_index; 84 } 85 86 87 /** 88 * Get LocalVariable object. 89 * 90 * This relies on that the instruction list has already been dumped to byte code or 91 * or that the `setPositions' methods has been called for the instruction list. 92 * 93 * Note that due to the conversion from byte code offset to InstructionHandle, 94 * it is impossible to tell the difference between a live range that ends BEFORE 95 * the last insturction of the method or a live range that ends AFTER the last 96 * instruction of the method. Hence the live_to_end flag to differentiate 97 * between these two cases. 98 * 99 * @param cp constant pool 100 */ getLocalVariable( final ConstantPoolGen cp )101 public LocalVariable getLocalVariable( final ConstantPoolGen cp ) { 102 int start_pc = 0; 103 int length = 0; 104 if ((start != null) && (end != null)) { 105 start_pc = start.getPosition(); 106 length = end.getPosition() - start_pc; 107 if ((end.getNext() == null) && live_to_end) { 108 length += end.getInstruction().getLength(); 109 } 110 } 111 final int name_index = cp.addUtf8(name); 112 final int signature_index = cp.addUtf8(type.getSignature()); 113 return new LocalVariable(start_pc, length, name_index, signature_index, index, cp 114 .getConstantPool(), orig_index); 115 } 116 117 setIndex( final int index )118 public void setIndex( final int index ) { 119 this.index = index; 120 } 121 122 getIndex()123 public int getIndex() { 124 return index; 125 } 126 127 getOrigIndex()128 public int getOrigIndex() { 129 return orig_index; 130 } 131 132 setLiveToEnd( final boolean live_to_end)133 public void setLiveToEnd( final boolean live_to_end) { 134 this.live_to_end = live_to_end; 135 } 136 137 getLiveToEnd()138 public boolean getLiveToEnd() { 139 return live_to_end; 140 } 141 142 143 @Override setName( final String name )144 public void setName( final String name ) { 145 this.name = name; 146 } 147 148 149 @Override getName()150 public String getName() { 151 return name; 152 } 153 154 155 @Override setType( final Type type )156 public void setType( final Type type ) { 157 this.type = type; 158 } 159 160 161 @Override getType()162 public Type getType() { 163 return type; 164 } 165 166 getStart()167 public InstructionHandle getStart() { 168 return start; 169 } 170 171 getEnd()172 public InstructionHandle getEnd() { 173 return end; 174 } 175 176 setStart( final InstructionHandle start )177 public void setStart( final InstructionHandle start ) { // TODO could be package-protected? 178 BranchInstruction.notifyTarget(this.start, start, this); 179 this.start = start; 180 } 181 182 setEnd( final InstructionHandle end )183 public void setEnd( final InstructionHandle end ) { // TODO could be package-protected? 184 BranchInstruction.notifyTarget(this.end, end, this); 185 this.end = end; 186 } 187 188 189 /** 190 * @param old_ih old target, either start or end 191 * @param new_ih new target 192 */ 193 @Override updateTarget( final InstructionHandle old_ih, final InstructionHandle new_ih )194 public void updateTarget( final InstructionHandle old_ih, final InstructionHandle new_ih ) { 195 boolean targeted = false; 196 if (start == old_ih) { 197 targeted = true; 198 setStart(new_ih); 199 } 200 if (end == old_ih) { 201 targeted = true; 202 setEnd(new_ih); 203 } 204 if (!targeted) { 205 throw new ClassGenException("Not targeting " + old_ih + ", but {" + start + ", " + end 206 + "}"); 207 } 208 } 209 210 /** 211 * Clear the references from and to this variable when it's removed. 212 */ dispose()213 void dispose() { 214 setStart(null); 215 setEnd(null); 216 } 217 218 /** 219 * @return true, if ih is target of this variable 220 */ 221 @Override containsTarget( final InstructionHandle ih )222 public boolean containsTarget( final InstructionHandle ih ) { 223 return (start == ih) || (end == ih); 224 } 225 226 227 @Override hashCode()228 public int hashCode() { 229 // If the user changes the name or type, problems with the targeter hashmap will occur. 230 // Note: index cannot be part of hash as it may be changed by the user. 231 return name.hashCode() ^ type.hashCode(); 232 } 233 234 235 /** 236 * We consider to local variables to be equal, if the use the same index and 237 * are valid in the same range. 238 */ 239 @Override equals( final Object o )240 public boolean equals( final Object o ) { 241 if (!(o instanceof LocalVariableGen)) { 242 return false; 243 } 244 final LocalVariableGen l = (LocalVariableGen) o; 245 return (l.index == index) && (l.start == start) && (l.end == end); 246 } 247 248 249 @Override toString()250 public String toString() { 251 return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; 252 } 253 254 255 @Override clone()256 public Object clone() { 257 try { 258 return super.clone(); 259 } catch (final CloneNotSupportedException e) { 260 throw new Error("Clone Not Supported"); // never happens 261 } 262 } 263 } 264