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 22 package com.sun.org.apache.bcel.internal.generic; 23 24 25 import com.sun.org.apache.bcel.internal.Constants; 26 import com.sun.org.apache.bcel.internal.classfile.*; 27 import java.util.Objects; 28 29 /** 30 * This class represents a local variable within a method. It contains its 31 * scope, name and type. The generated LocalVariable object can be obtained 32 * with getLocalVariable which needs the instruction list and the constant 33 * pool as parameters. 34 * 35 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 36 * @see LocalVariable 37 * @see MethodGen 38 */ 39 public class LocalVariableGen 40 implements InstructionTargeter, NamedAndTyped, Cloneable, 41 java.io.Serializable 42 { 43 private final int index; 44 private String name; 45 private Type type; 46 private InstructionHandle start, end; 47 48 /** 49 * Generate a local variable that with index `index'. Note that double and long 50 * variables need two indexs. Index indices have to be provided by the user. 51 * 52 * @param index index of local variable 53 * @param name its name 54 * @param type its type 55 * @param start from where the instruction is valid (null means from the start) 56 * @param end until where the instruction is valid (null means to the end) 57 */ 58 public LocalVariableGen(int index, String name, Type type, 59 InstructionHandle start, InstructionHandle end) { 60 if((index < 0) || (index > Constants.MAX_SHORT)) 61 throw new ClassGenException("Invalid index index: " + index); 62 63 this.name = name; 64 this.type = type; 65 this.index = index; 66 setStart(start); 67 setEnd(end); 68 } 69 70 /** 71 * Get LocalVariable object. 72 * 73 * This relies on that the instruction list has already been dumped to byte code or 74 * or that the `setPositions' methods has been called for the instruction list. 75 * 76 * Note that for local variables whose scope end at the last 77 * instruction of the method's code, the JVM specification is ambiguous: 78 * both a start_pc+length ending at the last instruction and 79 * start_pc+length ending at first index beyond the end of the code are 80 * valid. 81 * 82 * @param il instruction list (byte code) which this variable belongs to 83 * @param cp constant pool 84 */ 85 public LocalVariable getLocalVariable(ConstantPoolGen cp) { 86 int start_pc = start.getPosition(); 87 int length = end.getPosition() - start_pc; 88 89 if(length > 0) 90 length += end.getInstruction().getLength(); 91 92 int name_index = cp.addUtf8(name); 93 int signature_index = cp.addUtf8(type.getSignature()); 94 95 return new LocalVariable(start_pc, length, name_index, 96 signature_index, index, cp.getConstantPool()); 97 } 98 99 public int getIndex() { return index; } 100 @Override 101 public void setName(String name) { this.name = name; } 102 @Override 103 public String getName() { return name; } 104 @Override 105 public void setType(Type type) { this.type = type; } 106 @Override 107 public Type getType() { return type; } 108 109 public InstructionHandle getStart() { return start; } 110 public InstructionHandle getEnd() { return end; } 111 112 /** 113 * Remove this from any known HashSet in which it might be registered. 114 */ 115 void notifyTargetChanging() { 116 // hashCode depends on 'index', 'start', and 'end'. 117 // Therefore before changing any of these values we 118 // need to unregister 'this' from any HashSet where 119 // this is registered, and then we need to add it 120 // back... 121 122 // Unregister 'this' from the HashSet held by 'start'. 123 BranchInstruction.notifyTargetChanging(this.start, this); 124 if (this.end != this.start) { 125 // Since hashCode() is going to change we need to unregister 126 // 'this' both form 'start' and 'end'. 127 // Unregister 'this' from the HashSet held by 'end'. 128 BranchInstruction.notifyTargetChanging(this.end, this); 129 } 130 } 131 132 /** 133 * Add back 'this' in all HashSet in which it should be registered. 134 **/ 135 void notifyTargetChanged() { 136 // hashCode depends on 'index', 'start', and 'end'. 137 // Therefore before changing any of these values we 138 // need to unregister 'this' from any HashSet where 139 // this is registered, and then we need to add it 140 // back... 141 142 // Register 'this' in the HashSet held by start. 143 BranchInstruction.notifyTargetChanged(this.start, this); 144 if (this.end != this.start) { 145 // Since hashCode() has changed we need to register 146 // 'this' again in 'end'. 147 // Add back 'this' in the HashSet held by 'end'. 148 BranchInstruction.notifyTargetChanged(this.end, this); 149 } 150 } 151 152 public final void setStart(InstructionHandle start) { 153 154 // Call notifyTargetChanging *before* modifying this, 155 // as the code triggered by notifyTargetChanging 156 // depends on this pointing to the 'old' start. 157 notifyTargetChanging(); 158 159 this.start = start; 160 161 // call notifyTargetChanged *after* modifying this, 162 // as the code triggered by notifyTargetChanged 163 // depends on this pointing to the 'new' start. 164 notifyTargetChanged(); 165 } 166 167 public final void setEnd(InstructionHandle end) { 168 // call notifyTargetChanging *before* modifying this, 169 // as the code triggered by notifyTargetChanging 170 // depends on this pointing to the 'old' end. 171 // Unregister 'this' from the HashSet held by the 'old' end. 172 notifyTargetChanging(); 173 174 this.end = end; 175 176 // call notifyTargetChanged *after* modifying this, 177 // as the code triggered by notifyTargetChanged 178 // depends on this pointing to the 'new' end. 179 // Register 'this' in the HashSet held by the 'new' end. 180 notifyTargetChanged(); 181 182 } 183 184 /** 185 * @param old_ih old target, either start or end 186 * @param new_ih new target 187 */ 188 @Override 189 public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) { 190 boolean targeted = false; 191 192 if(start == old_ih) { 193 targeted = true; 194 setStart(new_ih); 195 } 196 197 if(end == old_ih) { 198 targeted = true; 199 setEnd(new_ih); 200 } 201 202 if(!targeted) 203 throw new ClassGenException("Not targeting " + old_ih + ", but {" + start + ", " + 204 end + "}"); 205 } 206 207 /** 208 * @return true, if ih is target of this variable 209 */ 210 @Override 211 public boolean containsTarget(InstructionHandle ih) { 212 return (start == ih) || (end == ih); 213 } 214 215 /** 216 * We consider two local variables to be equal, if they use the same index and 217 * are valid in the same range. 218 */ 219 @Override 220 public boolean equals(Object o) { 221 if (o==this) 222 return true; 223 224 if(!(o instanceof LocalVariableGen)) 225 return false; 226 227 LocalVariableGen l = (LocalVariableGen)o; 228 return (l.index == index) && (l.start == start) && (l.end == end); 229 } 230 231 @Override 232 public int hashCode() { 233 int hash = 7; 234 hash = 59 * hash + this.index; 235 hash = 59 * hash + Objects.hashCode(this.start); 236 hash = 59 * hash + Objects.hashCode(this.end); 237 return hash; 238 } 239 240 @Override 241 public String toString() { 242 return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; 243 } 244 245 @Override 246 public Object clone() { 247 try { 248 return super.clone(); 249 } catch(CloneNotSupportedException e) { 250 System.err.println(e); 251 return null; 252 } 253 } 254 } | 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 * This class represents a local variable within a method. It contains its 28 * scope, name and type. The generated LocalVariable object can be obtained with 29 * getLocalVariable which needs the instruction list and the constant pool as 30 * parameters. 31 * 32 * @version $Id: LocalVariableGen.java 1749603 2016-06-21 20:50:19Z ggregory $ 33 * @see LocalVariable 34 * @see MethodGen 35 */ 36 public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable { 37 38 private int index; 39 private String name; 40 private Type type; 41 private InstructionHandle start; 42 private InstructionHandle end; 43 44 /** 45 * Generate a local variable that with index `index'. Note that double and 46 * long variables need two indexs. Index indices have to be provided by the 47 * user. 48 * 49 * @param index index of local variable 50 * @param name its name 51 * @param type its type 52 * @param start from where the instruction is valid (null means from the 53 * 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, 57 final InstructionHandle start, 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 } 67 68 /** 69 * Get LocalVariable object. 70 * 71 * This relies on that the instruction list has already been dumped to byte 72 * code or or that the `setPositions' methods has been called for the 73 * instruction list. 74 * 75 * Note that for local variables whose scope end at the last instruction of 76 * the method's code, the JVM specification is ambiguous: both a 77 * start_pc+length ending at the last instruction and start_pc+length ending 78 * at first index beyond the end of the code are valid. 79 * 80 * @param cp constant pool 81 */ 82 public LocalVariable getLocalVariable(final ConstantPoolGen cp) { 83 int start_pc = 0; 84 int length = 0; 85 if ((start != null) && (end != null)) { 86 start_pc = start.getPosition(); 87 length = end.getPosition() - start_pc; 88 if (end.getNext() == null) { 89 length += end.getInstruction().getLength(); 90 } 91 } 92 final int name_index = cp.addUtf8(name); 93 final int signature_index = cp.addUtf8(type.getSignature()); 94 return new LocalVariable(start_pc, length, name_index, signature_index, index, cp 95 .getConstantPool()); 96 } 97 98 public void setIndex(final int index) { 99 this.index = index; 100 } 101 102 public int getIndex() { 103 return index; 104 } 105 106 @Override 107 public void setName(final String name) { 108 this.name = name; 109 } 110 111 @Override 112 public String getName() { 113 return name; 114 } 115 116 @Override 117 public void setType(final Type type) { 118 this.type = type; 119 } 120 121 @Override 122 public Type getType() { 123 return type; 124 } 125 126 public InstructionHandle getStart() { 127 return start; 128 } 129 130 public InstructionHandle getEnd() { 131 return end; 132 } 133 134 public void setStart(final InstructionHandle start) { // TODO could be package-protected? 135 BranchInstruction.notifyTarget(this.start, start, this); 136 this.start = start; 137 } 138 139 public void setEnd(final InstructionHandle end) { // TODO could be package-protected? 140 BranchInstruction.notifyTarget(this.end, end, this); 141 this.end = end; 142 } 143 144 /** 145 * @param old_ih old target, either start or end 146 * @param new_ih new target 147 */ 148 @Override 149 public void updateTarget(final InstructionHandle old_ih, final InstructionHandle new_ih) { 150 boolean targeted = false; 151 if (start == old_ih) { 152 targeted = true; 153 setStart(new_ih); 154 } 155 if (end == old_ih) { 156 targeted = true; 157 setEnd(new_ih); 158 } 159 if (!targeted) { 160 throw new ClassGenException("Not targeting " + old_ih + ", but {" + start + ", " + end 161 + "}"); 162 } 163 } 164 165 /** 166 * Clear the references from and to this variable when it's removed. 167 */ 168 void dispose() { 169 setStart(null); 170 setEnd(null); 171 } 172 173 /** 174 * @return true, if ih is target of this variable 175 */ 176 @Override 177 public boolean containsTarget(final InstructionHandle ih) { 178 return (start == ih) || (end == ih); 179 } 180 181 @Override 182 public int hashCode() { 183 // If the user changes the name or type, problems with the targeter hashmap will occur. 184 // Note: index cannot be part of hash as it may be changed by the user. 185 return name.hashCode() ^ type.hashCode(); 186 } 187 188 /** 189 * We consider to local variables to be equal, if the use the same index and 190 * are valid in the same range. 191 */ 192 @Override 193 public boolean equals(final Object o) { 194 if (!(o instanceof LocalVariableGen)) { 195 return false; 196 } 197 final LocalVariableGen l = (LocalVariableGen) o; 198 return (l.index == index) && (l.start == start) && (l.end == end); 199 } 200 201 @Override 202 public String toString() { 203 return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; 204 } 205 206 @Override 207 public Object clone() { 208 try { 209 return super.clone(); 210 } catch (final CloneNotSupportedException e) { 211 throw new Error("Clone Not Supported"); // never happens 212 } 213 } 214 } |