001 package edu.rice.cs.cunit.classFile.attributes;
002
003 import edu.rice.cs.cunit.classFile.ClassFileTools;
004 import edu.rice.cs.cunit.classFile.attributes.visitors.IAttributeVisitor;
005 import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable;
006 import edu.rice.cs.cunit.classFile.constantPool.AUTFPoolInfo;
007 import edu.rice.cs.cunit.classFile.constantPool.ConstantPool;
008 import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckUTFVisitor;
009 import edu.rice.cs.cunit.util.Types;
010
011 /**
012 * Represents the LocalVariableTable attribute in a class file.
013 *
014 * @author Mathias Ricken
015 */
016 public class LocalVariableTableAttributeInfo extends AAttributeInfo {
017 /**
018 * Storage class for line number/program counter _pairs.
019 */
020 public static class LocalVariableRecord {
021 public int startPC;
022 public int length;
023 public AUTFPoolInfo name;
024 public AUTFPoolInfo descriptor;
025 public int index;
026
027 public LocalVariableRecord(int startPC,
028 int length,
029 AUTFPoolInfo name,
030 AUTFPoolInfo descriptor,
031 int index) {
032 this.startPC = startPC;
033 this.length = length;
034 this.name = name;
035 this.descriptor = descriptor;
036 this.index = index;
037 }
038 }
039
040 /**
041 * Constructor.
042 *
043 * @param name attribute name
044 * @param data attribute data
045 * @param cp constant pool
046 *
047 * @throws ClassFormatError
048 */
049 public LocalVariableTableAttributeInfo(AUTFPoolInfo name, byte[] data, ConstantPool cp) throws ClassFormatError {
050 super(name, data, cp);
051 }
052
053 /**
054 * Return the number of local variable records.
055 *
056 * @return number of local variables
057 *
058 * @throws ClassFormatError
059 */
060 public int getLocalVariableCount() {
061 int res = Types.ushortFromBytes(_data, 0);
062 assert(res <= 0xffff);
063 return res;
064 }
065
066 /**
067 * Return a copy of the local variable records.
068 *
069 * @return list of local variable records
070 *
071 * @throws ClassFormatError
072 */
073 public LocalVariableRecord[] getLocalVariables() throws ClassFormatError {
074 int count = getLocalVariableCount();
075 LocalVariableRecord[] lvr = new LocalVariableRecord[count];
076 for(int i = 0; i < count; ++i) {
077 lvr[i] = new LocalVariableRecord(Types.ushortFromBytes(_data, 2 + 10 * i),
078 Types.ushortFromBytes(_data, 4 + 10 * i),
079 _constantPool.get(Types.ushortFromBytes(_data, 6 + 10 * i)).execute(CheckUTFVisitor.singleton(), null),
080 _constantPool.get(Types.ushortFromBytes(_data, 8 + 10 * i)).execute(CheckUTFVisitor.singleton(), null),
081 Types.ushortFromBytes(_data, 10 + 10 * i));
082 }
083 return lvr;
084 }
085
086 /**
087 * Set the local variable records.
088 *
089 * @param lnr array of local variable records
090 */
091 public void setLocalVariables(LocalVariableRecord[] lnr) {
092 byte[] newData = new byte[2 + 10 * lnr.length];
093 Types.bytesFromShort((short)lnr.length, newData, 0);
094 for(int i = 0; i < lnr.length; ++i) {
095 Types.bytesFromShort((short)(0xffff & lnr[i].startPC), newData, 2 + 10 * i);
096 Types.bytesFromShort((short)(0xffff & lnr[i].length), newData, 4 + 10 * i);
097 Types.bytesFromShort(_constantPool.indexOf(lnr[i].name), newData, 6 + 10 * i);
098 Types.bytesFromShort(_constantPool.indexOf(lnr[i].descriptor), newData, 8 + 10 * i);
099 Types.bytesFromShort((short)(0xffff & lnr[i].index), newData, 10 + 10 * i);
100 }
101 setData(newData);
102 }
103
104 /**
105 * Execute a visitor on this attribute.
106 *
107 * @param visitor visitor
108 * @param param visitor-specific parameter
109 *
110 * @return visitor-specific return value
111 */
112 public <R, D> R execute(IAttributeVisitor<R, D> visitor, D param) {
113 return visitor.localVariableTableCase(this, param);
114 }
115
116 /**
117 * Return a human-readable version of this attribute.
118 *
119 * @return string
120 */
121 public String toString() {
122 StringBuilder x = new StringBuilder();
123 x.append(_name + " <" + getLocalVariableCount() + " local variables{ ");
124 boolean first = true;
125 for(LocalVariableRecord lvrs : getLocalVariables()) {
126 if (first) {
127 first = false;
128 }
129 else {
130 x.append(", ");
131 }
132 x.append("(PC=" + lvrs.startPC + ".." + (lvrs.startPC + lvrs.length) + ", " +
133 ClassFileTools.getTypeString(lvrs.descriptor.toString(), lvrs.name.toString()) +
134 ", index " + lvrs.index + ")");
135 }
136 x.append(" } >");
137 return x.toString();
138 }
139
140 /**
141 * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
142 *
143 * @param startPC program counter to start at
144 * @param deltaPC change in program counter values
145 */
146 public void adjustPC(int startPC, int deltaPC) {
147 LocalVariableRecord[] lvrs = getLocalVariables();
148 for(LocalVariableRecord l : lvrs) {
149 if (l.startPC >= startPC) {
150 // Debug.out.println("Adjusted LocalVariableTable.lvrs[].startPC: "+l.startPC+" --> "+(l.startPC+deltaPC));
151 l.startPC += deltaPC;
152 }
153
154 // if the startPC falls between the start and the end of this record, increase length
155 if ((l.startPC <= startPC) && (l.startPC + l.length >= startPC)) {
156 // Debug.out.println("Adjusted LocalVariableTable.lvrs[].length: "+l.length+" --> "+(l.length+deltaPC));
157 l.length += deltaPC;
158 }
159 }
160 setLocalVariables(lvrs);
161 }
162
163 /**
164 * Translate the program counter values contained in this attribute from an old line number table to a new one.
165 *
166 * @param index critical point (insertion or deletion point)
167 * @param deltaIndex delta value to add to all old line numbers greater than the critical point
168 * @param oldLnt old line number table
169 * @param newLnt new line number table
170 */
171 public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
172 LocalVariableRecord[] lvrs = getLocalVariables();
173 for(LocalVariableRecord l : lvrs) {
174 int oldLineNo = oldLnt.getLineNumber(l.startPC);
175 int oldEndLineNo = oldLnt.getLineNumber(l.startPC + l.length);
176
177 oldEndLineNo += (oldEndLineNo > index) ? deltaIndex : 0;
178 oldLineNo += (oldLineNo > index) ? deltaIndex : 0;
179
180 l.startPC = newLnt.getPC(oldLineNo);
181 l.length = (newLnt.getPC(oldEndLineNo) - l.startPC);
182 }
183 setLocalVariables(lvrs);
184 }
185
186 /**
187 * Creates and returns a copy of this object.
188 */
189 public Object clone() throws CloneNotSupportedException {
190 return super.clone();
191 }
192
193 /**
194 * Returns the name of the attribute as it appears in the class file.
195 *
196 * @return name of the attribute.
197 */
198 public static String getAttributeName() {
199 return "LocalVariableTable";
200 }
201 }