LocalVariableTable.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.classfile;

  18. import java.io.DataInput;
  19. import java.io.DataOutputStream;
  20. import java.io.IOException;
  21. import java.util.Arrays;
  22. import java.util.Iterator;
  23. import java.util.stream.Stream;

  24. import org.apache.bcel.Const;
  25. import org.apache.bcel.util.Args;

  26. /**
  27.  * This class represents colection of local variables in a method. This attribute is contained in the <em>Code</em>
  28.  * attribute.
  29.  *
  30.  * @see Code
  31.  * @see LocalVariable
  32.  */
  33. public class LocalVariableTable extends Attribute implements Iterable<LocalVariable> {

  34.     private static final LocalVariable[] EMPTY_ARRAY = {};

  35.     private LocalVariable[] localVariableTable; // variables

  36.     /**
  37.      * Constructs object from input stream.
  38.      *
  39.      * @param nameIndex Index in constant pool
  40.      * @param length Content length in bytes
  41.      * @param input Input stream
  42.      * @param constantPool Array of constants
  43.      * @throws IOException if an I/O error occurs.
  44.      */
  45.     LocalVariableTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
  46.         this(nameIndex, length, (LocalVariable[]) null, constantPool);
  47.         final int localVariableTableLength = input.readUnsignedShort();
  48.         localVariableTable = new LocalVariable[localVariableTableLength];
  49.         for (int i = 0; i < localVariableTableLength; i++) {
  50.             localVariableTable[i] = new LocalVariable(input, constantPool);
  51.         }
  52.     }

  53.     /**
  54.      * @param nameIndex Index in constant pool to 'LocalVariableTable'
  55.      * @param length Content length in bytes
  56.      * @param localVariableTable Table of local variables
  57.      * @param constantPool Array of constants
  58.      */
  59.     public LocalVariableTable(final int nameIndex, final int length, final LocalVariable[] localVariableTable, final ConstantPool constantPool) {
  60.         super(Const.ATTR_LOCAL_VARIABLE_TABLE, nameIndex, length, constantPool);
  61.         this.localVariableTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY;
  62.         Args.requireU2(this.localVariableTable.length, "localVariableTable.length");
  63.     }

  64.     /**
  65.      * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
  66.      * physical copy.
  67.      *
  68.      * @param c Source to copy.
  69.      */
  70.     public LocalVariableTable(final LocalVariableTable c) {
  71.         this(c.getNameIndex(), c.getLength(), c.getLocalVariableTable(), c.getConstantPool());
  72.     }

  73.     /**
  74.      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
  75.      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
  76.      *
  77.      * @param v Visitor object
  78.      */
  79.     @Override
  80.     public void accept(final Visitor v) {
  81.         v.visitLocalVariableTable(this);
  82.     }

  83.     /**
  84.      * @return deep copy of this attribute
  85.      */
  86.     @Override
  87.     public Attribute copy(final ConstantPool constantPool) {
  88.         final LocalVariableTable c = (LocalVariableTable) clone();
  89.         c.localVariableTable = new LocalVariable[localVariableTable.length];
  90.         Arrays.setAll(c.localVariableTable, i -> localVariableTable[i].copy());
  91.         c.setConstantPool(constantPool);
  92.         return c;
  93.     }

  94.     /**
  95.      * Dump local variable table attribute to file stream in binary format.
  96.      *
  97.      * @param file Output file stream
  98.      * @throws IOException if an I/O error occurs.
  99.      */
  100.     @Override
  101.     public final void dump(final DataOutputStream file) throws IOException {
  102.         super.dump(file);
  103.         file.writeShort(localVariableTable.length);
  104.         for (final LocalVariable variable : localVariableTable) {
  105.             variable.dump(file);
  106.         }
  107.     }

  108.     /**
  109.      *
  110.      * @param index the variable slot
  111.      *
  112.      * @return the first LocalVariable that matches the slot or null if not found
  113.      *
  114.      * @deprecated since 5.2 because multiple variables can share the same slot, use getLocalVariable(int index, int pc)
  115.      *             instead.
  116.      */
  117.     @java.lang.Deprecated
  118.     public final LocalVariable getLocalVariable(final int index) {
  119.         for (final LocalVariable variable : localVariableTable) {
  120.             if (variable.getIndex() == index) {
  121.                 return variable;
  122.             }
  123.         }
  124.         return null;
  125.     }

  126.     /**
  127.      *
  128.      * @param index the variable slot
  129.      * @param pc the current pc that this variable is alive
  130.      *
  131.      * @return the LocalVariable that matches or null if not found
  132.      */
  133.     public final LocalVariable getLocalVariable(final int index, final int pc) {
  134.         for (final LocalVariable variable : localVariableTable) {
  135.             if (variable.getIndex() == index) {
  136.                 final int startPc = variable.getStartPC();
  137.                 final int endPc = startPc + variable.getLength();
  138.                 if (pc >= startPc && pc <= endPc) {
  139.                     return variable;
  140.                 }
  141.             }
  142.         }
  143.         return null;
  144.     }

  145.     /**
  146.      * @return Array of local variables of method.
  147.      */
  148.     public final LocalVariable[] getLocalVariableTable() {
  149.         return localVariableTable;
  150.     }

  151.     public final int getTableLength() {
  152.         return localVariableTable.length;
  153.     }

  154.     @Override
  155.     public Iterator<LocalVariable> iterator() {
  156.         return Stream.of(localVariableTable).iterator();
  157.     }

  158.     public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
  159.         this.localVariableTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY;
  160.     }

  161.     /**
  162.      * @return String representation.
  163.      */
  164.     @Override
  165.     public final String toString() {
  166.         final StringBuilder buf = new StringBuilder();
  167.         for (int i = 0; i < localVariableTable.length; i++) {
  168.             buf.append(localVariableTable[i]);
  169.             if (i < localVariableTable.length - 1) {
  170.                 buf.append('\n');
  171.             }
  172.         }
  173.         return buf.toString();
  174.     }
  175. }