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 1749603 2016-06-21 20:50:19Z 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 041 042 /** 043 * Generate a local variable that with index `index'. Note that double and long 044 * variables need two indexs. Index indices have to be provided by the user. 045 * 046 * @param index index of local variable 047 * @param name its name 048 * @param type its type 049 * @param start from where the instruction is valid (null means from the start) 050 * @param end until where the instruction is valid (null means to the end) 051 */ 052 public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, 053 final InstructionHandle end) { 054 if ((index < 0) || (index > Const.MAX_SHORT)) { 055 throw new ClassGenException("Invalid index index: " + index); 056 } 057 this.name = name; 058 this.type = type; 059 this.index = index; 060 setStart(start); 061 setEnd(end); 062 } 063 064 065 /** 066 * Get LocalVariable object. 067 * 068 * This relies on that the instruction list has already been dumped to byte code or 069 * or that the `setPositions' methods has been called for the instruction list. 070 * 071 * Note that for local variables whose scope end at the last 072 * instruction of the method's code, the JVM specification is ambiguous: 073 * both a start_pc+length ending at the last instruction and 074 * start_pc+length ending at first index beyond the end of the code are 075 * valid. 076 * 077 * @param cp constant pool 078 */ 079 public LocalVariable getLocalVariable( final ConstantPoolGen cp ) { 080 int start_pc = 0; 081 int length = 0; 082 if ((start != null) && (end != null)) { 083 start_pc = start.getPosition(); 084 length = end.getPosition() - start_pc; 085 if (end.getNext() == null) { 086 length += end.getInstruction().getLength(); 087 } 088 } 089 final int name_index = cp.addUtf8(name); 090 final int signature_index = cp.addUtf8(type.getSignature()); 091 return new LocalVariable(start_pc, length, name_index, signature_index, index, cp 092 .getConstantPool()); 093 } 094 095 096 public void setIndex( final int index ) { 097 this.index = index; 098 } 099 100 101 public int getIndex() { 102 return index; 103 } 104 105 106 @Override 107 public void setName( final String name ) { 108 this.name = name; 109 } 110 111 112 @Override 113 public String getName() { 114 return name; 115 } 116 117 118 @Override 119 public void setType( final Type type ) { 120 this.type = type; 121 } 122 123 124 @Override 125 public Type getType() { 126 return type; 127 } 128 129 130 public InstructionHandle getStart() { 131 return start; 132 } 133 134 135 public InstructionHandle getEnd() { 136 return end; 137 } 138 139 140 public void setStart( final InstructionHandle start ) { // TODO could be package-protected? 141 BranchInstruction.notifyTarget(this.start, start, this); 142 this.start = start; 143 } 144 145 146 public void setEnd( final InstructionHandle end ) { // TODO could be package-protected? 147 BranchInstruction.notifyTarget(this.end, end, this); 148 this.end = end; 149 } 150 151 152 /** 153 * @param old_ih old target, either start or end 154 * @param new_ih new target 155 */ 156 @Override 157 public void updateTarget( final InstructionHandle old_ih, final InstructionHandle new_ih ) { 158 boolean targeted = false; 159 if (start == old_ih) { 160 targeted = true; 161 setStart(new_ih); 162 } 163 if (end == old_ih) { 164 targeted = true; 165 setEnd(new_ih); 166 } 167 if (!targeted) { 168 throw new ClassGenException("Not targeting " + old_ih + ", but {" + start + ", " + end 169 + "}"); 170 } 171 } 172 173 /** 174 * Clear the references from and to this variable when it's removed. 175 */ 176 void dispose() { 177 setStart(null); 178 setEnd(null); 179 } 180 181 /** 182 * @return true, if ih is target of this variable 183 */ 184 @Override 185 public boolean containsTarget( final InstructionHandle ih ) { 186 return (start == ih) || (end == ih); 187 } 188 189 190 @Override 191 public int hashCode() { 192 // If the user changes the name or type, problems with the targeter hashmap will occur. 193 // Note: index cannot be part of hash as it may be changed by the user. 194 return name.hashCode() ^ type.hashCode(); 195 } 196 197 198 /** 199 * We consider to local variables to be equal, if the use the same index and 200 * are valid in the same range. 201 */ 202 @Override 203 public boolean equals( final Object o ) { 204 if (!(o instanceof LocalVariableGen)) { 205 return false; 206 } 207 final LocalVariableGen l = (LocalVariableGen) o; 208 return (l.index == index) && (l.start == start) && (l.end == end); 209 } 210 211 212 @Override 213 public String toString() { 214 return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")"; 215 } 216 217 218 @Override 219 public Object clone() { 220 try { 221 return super.clone(); 222 } catch (final CloneNotSupportedException e) { 223 throw new Error("Clone Not Supported"); // never happens 224 } 225 } 226}