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 }