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 */ 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 */ 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 */ 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 120 public void setIndex( final int index ) { 121 this.index = index; 122 } 123 124 125 public int getIndex() { 126 return index; 127 } 128 129 130 public int getOrigIndex() { 131 return orig_index; 132 } 133 134 135 public void setLiveToEnd( final boolean live_to_end) { 136 this.live_to_end = live_to_end; 137 } 138 139 140 public boolean getLiveToEnd() { 141 return live_to_end; 142 } 143 144 145 @Override 146 public void setName( final String name ) { 147 this.name = name; 148 } 149 150 151 @Override 152 public String getName() { 153 return name; 154 } 155 156 157 @Override 158 public void setType( final Type type ) { 159 this.type = type; 160 } 161 162 163 @Override 164 public Type getType() { 165 return type; 166 } 167 168 169 public InstructionHandle getStart() { 170 return start; 171 } 172 173 174 public InstructionHandle getEnd() { 175 return end; 176 } 177 178 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 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 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 */ 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 224 public boolean containsTarget( final InstructionHandle ih ) { 225 return (start == ih) || (end == ih); 226 } 227 228 229 @Override 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 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 252 public String toString() { 253 return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; 254 } 255 256 257 @Override 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 }