LocalVariableGen.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.bcel.generic;

  18. import org.apache.bcel.Const;
  19. import org.apache.bcel.classfile.LocalVariable;

  20. /**
  21.  * Represents a local variable within a method. It contains its scope, name and type. The generated LocalVariable object
  22.  * can be obtained with getLocalVariable which needs the instruction list and the constant pool as parameters.
  23.  *
  24.  * @see LocalVariable
  25.  * @see MethodGen
  26.  */
  27. public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Cloneable {

  28.     private int index;
  29.     private String name;
  30.     private Type type;
  31.     private InstructionHandle start;
  32.     private InstructionHandle end;
  33.     private int origIndex; // never changes; used to match up with LocalVariableTypeTable entries
  34.     private boolean liveToEnd;

  35.     /**
  36.      * Generate a local variable that with index 'index'. Note that double and long variables need two indexs. Index indices
  37.      * have to be provided by the user.
  38.      *
  39.      * @param index index of local variable
  40.      * @param name its name
  41.      * @param type its type
  42.      * @param start from where the instruction is valid (null means from the start)
  43.      * @param end until where the instruction is valid (null means to the end)
  44.      */
  45.     public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, final InstructionHandle end) {
  46.         if (index < 0 || index > Const.MAX_SHORT) {
  47.             throw new ClassGenException("Invalid index: " + index);
  48.         }
  49.         this.name = name;
  50.         this.type = type;
  51.         this.index = index;
  52.         setStart(start);
  53.         setEnd(end);
  54.         this.origIndex = index;
  55.         this.liveToEnd = end == null;
  56.     }

  57.     /**
  58.      * Generates a local variable that with index 'index'. Note that double and long variables need two indexs. Index
  59.      * indices have to be provided by the user.
  60.      *
  61.      * @param index index of local variable
  62.      * @param name its name
  63.      * @param type its type
  64.      * @param start from where the instruction is valid (null means from the start)
  65.      * @param end until where the instruction is valid (null means to the end)
  66.      * @param origIndex index of local variable prior to any changes to index
  67.      */
  68.     public LocalVariableGen(final int index, final String name, final Type type, final InstructionHandle start, final InstructionHandle end,
  69.         final int origIndex) {
  70.         this(index, name, type, start, end);
  71.         this.origIndex = origIndex;
  72.     }

  73.     @Override
  74.     public Object clone() {
  75.         try {
  76.             return super.clone();
  77.         } catch (final CloneNotSupportedException e) {
  78.             throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
  79.         }
  80.     }

  81.     /**
  82.      * @return true, if ih is target of this variable
  83.      */
  84.     @Override
  85.     public boolean containsTarget(final InstructionHandle ih) {
  86.         return start == ih || end == ih;
  87.     }

  88.     /**
  89.      * Clear the references from and to this variable when it's removed.
  90.      */
  91.     void dispose() {
  92.         setStart(null);
  93.         setEnd(null);
  94.     }

  95.     /**
  96.      * We consider to local variables to be equal, if the use the same index and are valid in the same range.
  97.      */
  98.     @Override
  99.     public boolean equals(final Object o) {
  100.         if (!(o instanceof LocalVariableGen)) {
  101.             return false;
  102.         }
  103.         final LocalVariableGen l = (LocalVariableGen) o;
  104.         return l.index == index && l.start == start && l.end == end;
  105.     }

  106.     public InstructionHandle getEnd() {
  107.         return end;
  108.     }

  109.     public int getIndex() {
  110.         return index;
  111.     }

  112.     public boolean getLiveToEnd() {
  113.         return liveToEnd;
  114.     }

  115.     /**
  116.      * Gets LocalVariable object.
  117.      *
  118.      * This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
  119.      * has been called for the instruction list.
  120.      *
  121.      * Note that due to the conversion from byte code offset to InstructionHandle, it is impossible to tell the difference
  122.      * between a live range that ends BEFORE the last insturction of the method or a live range that ends AFTER the last
  123.      * instruction of the method. Hence the liveToEnd flag to differentiate between these two cases.
  124.      *
  125.      * @param cp constant pool
  126.      */
  127.     public LocalVariable getLocalVariable(final ConstantPoolGen cp) {
  128.         int startPc = 0;
  129.         int length = 0;
  130.         if (start != null && end != null) {
  131.             startPc = start.getPosition();
  132.             length = end.getPosition() - startPc;
  133.             if (end.getNext() == null && liveToEnd) {
  134.                 length += end.getInstruction().getLength();
  135.             }
  136.         }
  137.         final int nameIndex = cp.addUtf8(name);
  138.         final int signatureIndex = cp.addUtf8(type.getSignature());
  139.         return new LocalVariable(startPc, length, nameIndex, signatureIndex, index, cp.getConstantPool(), origIndex);
  140.     }

  141.     @Override
  142.     public String getName() {
  143.         return name;
  144.     }

  145.     public int getOrigIndex() {
  146.         return origIndex;
  147.     }

  148.     public InstructionHandle getStart() {
  149.         return start;
  150.     }

  151.     @Override
  152.     public Type getType() {
  153.         return type;
  154.     }

  155.     @Override
  156.     public int hashCode() {
  157.         // If the user changes the name or type, problems with the targeter hashmap will occur.
  158.         // Note: index cannot be part of hash as it may be changed by the user.
  159.         return name.hashCode() ^ type.hashCode();
  160.     }

  161.     public void setEnd(final InstructionHandle end) { // TODO could be package-protected?
  162.         BranchInstruction.notifyTarget(this.end, end, this);
  163.         this.end = end;
  164.     }

  165.     public void setIndex(final int index) {
  166.         this.index = index;
  167.     }

  168.     public void setLiveToEnd(final boolean liveToEnd) {
  169.         this.liveToEnd = liveToEnd;
  170.     }

  171.     @Override
  172.     public void setName(final String name) {
  173.         this.name = name;
  174.     }

  175.     public void setStart(final InstructionHandle start) { // TODO could be package-protected?
  176.         BranchInstruction.notifyTarget(this.start, start, this);
  177.         this.start = start;
  178.     }

  179.     @Override
  180.     public void setType(final Type type) {
  181.         this.type = type;
  182.     }

  183.     @Override
  184.     public String toString() {
  185.         return "LocalVariableGen(" + name + ", " + type + ", " + start + ", " + end + ")";
  186.     }

  187.     /**
  188.      * @param oldIh old target, either start or end
  189.      * @param newIh new target
  190.      */
  191.     @Override
  192.     public void updateTarget(final InstructionHandle oldIh, final InstructionHandle newIh) {
  193.         boolean targeted = false;
  194.         if (start == oldIh) {
  195.             targeted = true;
  196.             setStart(newIh);
  197.         }
  198.         if (end == oldIh) {
  199.             targeted = true;
  200.             setEnd(newIh);
  201.         }
  202.         if (!targeted) {
  203.             throw new ClassGenException("Not targeting " + oldIh + ", but {" + start + ", " + end + "}");
  204.         }
  205.     }
  206. }