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