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 }