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 */ 017package org.apache.bcel.classfile; 018 019import java.io.DataInput; 020import java.io.DataOutputStream; 021import java.io.IOException; 022import java.util.Arrays; 023import java.util.Iterator; 024import java.util.stream.Stream; 025 026import org.apache.bcel.Const; 027import org.apache.bcel.util.Args; 028 029/** 030 * This class represents colection of local variables in a method. This attribute is contained in the <em>Code</em> 031 * attribute. 032 * 033 * @see Code 034 * @see LocalVariable 035 */ 036public class LocalVariableTable extends Attribute implements Iterable<LocalVariable> { 037 038 private static final LocalVariable[] EMPTY_ARRAY = {}; 039 040 private LocalVariable[] localVariableTable; // variables 041 042 /** 043 * Constructs object from input stream. 044 * 045 * @param nameIndex Index in constant pool 046 * @param length Content length in bytes 047 * @param input Input stream 048 * @param constantPool Array of constants 049 * @throws IOException if an I/O error occurs. 050 */ 051 LocalVariableTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { 052 this(nameIndex, length, (LocalVariable[]) null, constantPool); 053 final int localVariableTableLength = input.readUnsignedShort(); 054 localVariableTable = new LocalVariable[localVariableTableLength]; 055 for (int i = 0; i < localVariableTableLength; i++) { 056 localVariableTable[i] = new LocalVariable(input, constantPool); 057 } 058 } 059 060 /** 061 * @param nameIndex Index in constant pool to 'LocalVariableTable' 062 * @param length Content length in bytes 063 * @param localVariableTable Table of local variables 064 * @param constantPool Array of constants 065 */ 066 public LocalVariableTable(final int nameIndex, final int length, final LocalVariable[] localVariableTable, final ConstantPool constantPool) { 067 super(Const.ATTR_LOCAL_VARIABLE_TABLE, nameIndex, length, constantPool); 068 this.localVariableTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY; 069 Args.requireU2(this.localVariableTable.length, "localVariableTable.length"); 070 } 071 072 /** 073 * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a 074 * physical copy. 075 * 076 * @param c Source to copy. 077 */ 078 public LocalVariableTable(final LocalVariableTable c) { 079 this(c.getNameIndex(), c.getLength(), c.getLocalVariableTable(), c.getConstantPool()); 080 } 081 082 /** 083 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 084 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 085 * 086 * @param v Visitor object 087 */ 088 @Override 089 public void accept(final Visitor v) { 090 v.visitLocalVariableTable(this); 091 } 092 093 /** 094 * @return deep copy of this attribute 095 */ 096 @Override 097 public Attribute copy(final ConstantPool constantPool) { 098 final LocalVariableTable c = (LocalVariableTable) clone(); 099 c.localVariableTable = new LocalVariable[localVariableTable.length]; 100 Arrays.setAll(c.localVariableTable, i -> localVariableTable[i].copy()); 101 c.setConstantPool(constantPool); 102 return c; 103 } 104 105 /** 106 * Dump local variable table attribute to file stream in binary format. 107 * 108 * @param file Output file stream 109 * @throws IOException if an I/O error occurs. 110 */ 111 @Override 112 public final void dump(final DataOutputStream file) throws IOException { 113 super.dump(file); 114 file.writeShort(localVariableTable.length); 115 for (final LocalVariable variable : localVariableTable) { 116 variable.dump(file); 117 } 118 } 119 120 /** 121 * 122 * @param index the variable slot 123 * 124 * @return the first LocalVariable that matches the slot or null if not found 125 * 126 * @deprecated since 5.2 because multiple variables can share the same slot, use getLocalVariable(int index, int pc) 127 * instead. 128 */ 129 @java.lang.Deprecated 130 public final LocalVariable getLocalVariable(final int index) { 131 for (final LocalVariable variable : localVariableTable) { 132 if (variable.getIndex() == index) { 133 return variable; 134 } 135 } 136 return null; 137 } 138 139 /** 140 * 141 * @param index the variable slot 142 * @param pc the current pc that this variable is alive 143 * 144 * @return the LocalVariable that matches or null if not found 145 */ 146 public final LocalVariable getLocalVariable(final int index, final int pc) { 147 for (final LocalVariable variable : localVariableTable) { 148 if (variable.getIndex() == index) { 149 final int startPc = variable.getStartPC(); 150 final int endPc = startPc + variable.getLength(); 151 if (pc >= startPc && pc <= endPc) { 152 return variable; 153 } 154 } 155 } 156 return null; 157 } 158 159 /** 160 * @return Array of local variables of method. 161 */ 162 public final LocalVariable[] getLocalVariableTable() { 163 return localVariableTable; 164 } 165 166 public final int getTableLength() { 167 return localVariableTable.length; 168 } 169 170 @Override 171 public Iterator<LocalVariable> iterator() { 172 return Stream.of(localVariableTable).iterator(); 173 } 174 175 public final void setLocalVariableTable(final LocalVariable[] localVariableTable) { 176 this.localVariableTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY; 177 } 178 179 /** 180 * @return String representation. 181 */ 182 @Override 183 public final String toString() { 184 final StringBuilder buf = new StringBuilder(); 185 for (int i = 0; i < localVariableTable.length; i++) { 186 buf.append(localVariableTable[i]); 187 if (i < localVariableTable.length - 1) { 188 buf.append('\n'); 189 } 190 } 191 return buf.toString(); 192 } 193}