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