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