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 */ 018package org.apache.bcel.generic; 019 020import org.apache.bcel.Const; 021import 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 1812325 2017-10-16 20:34:31Z ggregory $ 030 * @see LocalVariable 031 * @see MethodGen 032 */ 033public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable { 034 035 private int index; 036 private String name; 037 private Type type; 038 private InstructionHandle start; 039 private InstructionHandle end; 040 private int orig_index; // never changes; used to match up with LocalVariableTypeTable entries 041 private boolean live_to_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(final int index, final String name, final Type type, final InstructionHandle start, 055 final InstructionHandle end) { 056 if ((index < 0) || (index > Const.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 this.orig_index = index; 065 this.live_to_end = end == null; 066 } 067 068 069 /** 070 * Generate a local variable that with index `index'. Note that double and long 071 * variables need two indexs. Index indices have to be provided by the user. 072 * 073 * @param index index of local variable 074 * @param name its name 075 * @param type its type 076 * @param start from where the instruction is valid (null means from the start) 077 * @param end until where the instruction is valid (null means to the end) 078 * @param orig_index index of local variable prior to any changes to index 079 */ 080 public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, 081 final InstructionHandle end, final int orig_index) { 082 this(index, name, type, start, end); 083 this.orig_index = orig_index; 084 } 085 086 087 /** 088 * Get LocalVariable object. 089 * 090 * This relies on that the instruction list has already been dumped to byte code or 091 * or that the `setPositions' methods has been called for the instruction list. 092 * 093 * Note that due to the conversion from byte code offset to InstructionHandle, 094 * it is impossible to tell the difference between a live range that ends BEFORE 095 * the last insturction of the method or a live range that ends AFTER the last 096 * instruction of the method. Hence the live_to_end flag to differentiate 097 * between these two cases. 098 * 099 * @param cp constant pool 100 */ 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 118 public void setIndex( final int index ) { 119 this.index = index; 120 } 121 122 123 public int getIndex() { 124 return index; 125 } 126 127 128 public int getOrigIndex() { 129 return orig_index; 130 } 131 132 133 public void setLiveToEnd( final boolean live_to_end) { 134 this.live_to_end = live_to_end; 135 } 136 137 138 public boolean getLiveToEnd() { 139 return live_to_end; 140 } 141 142 143 @Override 144 public void setName( final String name ) { 145 this.name = name; 146 } 147 148 149 @Override 150 public String getName() { 151 return name; 152 } 153 154 155 @Override 156 public void setType( final Type type ) { 157 this.type = type; 158 } 159 160 161 @Override 162 public Type getType() { 163 return type; 164 } 165 166 167 public InstructionHandle getStart() { 168 return start; 169 } 170 171 172 public InstructionHandle getEnd() { 173 return end; 174 } 175 176 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 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 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 */ 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 222 public boolean containsTarget( final InstructionHandle ih ) { 223 return (start == ih) || (end == ih); 224 } 225 226 227 @Override 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 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 250 public String toString() { 251 return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; 252 } 253 254 255 @Override 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}