001 package edu.rice.cs.cunit.classFile.attributes;
002
003 import edu.rice.cs.cunit.classFile.ClassFile;
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.APoolInfo;
007 import edu.rice.cs.cunit.classFile.constantPool.ASCIIPoolInfo;
008 import edu.rice.cs.cunit.classFile.constantPool.AUTFPoolInfo;
009 import edu.rice.cs.cunit.classFile.constantPool.ConstantPool;
010 import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckUTFVisitor;
011 import edu.rice.cs.cunit.instrumentors.IInstrumentationStrategy;
012
013 import java.io.ByteArrayOutputStream;
014 import java.util.List;
015 import java.util.Collection;
016
017 /**
018 * Represents the Instrumentation attribute in a class file.
019 *
020 * @author Mathias Ricken
021 */
022 public class InstrumentationAttributeInfo extends AAttributeInfo {
023 /**
024 * Constructor.
025 *
026 * @param name attribute name
027 * @param data attribute data
028 * @param cp constant pool
029 *
030 * @throws ClassFormatError
031 */
032 public InstrumentationAttributeInfo(AUTFPoolInfo name, byte[] data, ConstantPool cp) throws ClassFormatError {
033 super(name, data, cp);
034 }
035
036 /**
037 * Return an array of instrumentator class names.
038 *
039 * @return array of instrumentator class names
040 *
041 * @throws ClassFormatError
042 */
043 public String[] getInstrumentatorClassNames() throws ClassFormatError {
044 String s = new String(_data);
045 return s.split(";");
046 }
047
048 /**
049 * Return the instrumentator class names as string.
050 *
051 * @return string with instrumentator class names
052 *
053 * @throws ClassFormatError
054 */
055 public String getInstrumentatorClassNameString() throws ClassFormatError {
056 return new String(_data);
057 }
058
059 /**
060 * Set the source file name information.
061 *
062 * @param classNames constant pool
063 */
064 public void setInstrumentatorClassNames(String[] classNames) {
065 StringBuilder sb = new StringBuilder();
066 for(String s: classNames) {
067 sb.append(';');
068 sb.append(s);
069 }
070 String s = sb.toString();
071 _data = new byte[s.length()-1];
072 System.arraycopy(s.toCharArray(), 1, _data, 0, s.length()-1);
073 }
074
075 /**
076 * Execute a visitor on this attribute.
077 *
078 * @param visitor visitor
079 * @param param visitor-specific parameter
080 *
081 * @return visitor-specific return value
082 */
083 public <R, D> R execute(IAttributeVisitor<R, D> visitor, D param) {
084 return visitor.instrumentationCase(this, param);
085 }
086
087 /**
088 * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
089 *
090 * @param startPC program counter to start at
091 * @param deltaPC change in program counter values
092 */
093 public void adjustPC(int startPC, int deltaPC) {
094 // nothing to do
095 }
096
097 /**
098 * Translate the program counter values contained in this attribute from an old line number table to a new one.
099 *
100 * @param index critical point (insertion or deletion point)
101 * @param deltaIndex delta value to add to all old line numbers greater than the critical point
102 * @param oldLnt old line number table
103 * @param newLnt new line number table
104 */
105 public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
106 // nothing to do
107 }
108
109 /**
110 * Creates and returns a copy of this object.
111 */
112 public Object clone() throws CloneNotSupportedException {
113 return super.clone();
114 }
115
116 /**
117 * Return a human-readable version of this attribute.
118 *
119 * @return string
120 */
121 public String toString() {
122 return "Instrumentors = "+getInstrumentatorClassNameString();
123 }
124
125 /**
126 * Name of this attribute.
127 */
128 public static final String NAME = "edu.rice.cs.cunit.Instrumentation";
129
130 /**
131 * Add the Instrumentation attribute with the given instrumentor class name string to the class file.
132 * @param cf class file
133 * @param s names of instrumentor classes, separated by ';'
134 */
135 public static void addInstrumentationAttributeInfo(ClassFile cf, String s) {
136 ByteArrayOutputStream baos = new ByteArrayOutputStream();
137 for(char ch: s.toCharArray()) {
138 baos.write((int)ch);
139 }
140
141 // add a new name for the attribute
142 int[] l;
143
144 AUTFPoolInfo attributeName = new ASCIIPoolInfo(NAME, cf.getConstantPool());
145 l = cf.addConstantPoolItems(new APoolInfo[]{attributeName});
146 attributeName = cf.getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null);
147
148 // remove if it already exists
149 AAttributeInfo existing = cf.getAttribute(NAME);
150 if (existing!=null) {
151 cf.getAttributes().remove(existing);
152 }
153
154 cf.addAttribute(new InstrumentationAttributeInfo(attributeName, baos.toByteArray(), cf.getConstantPool()));
155 }
156
157 /**
158 * Add the Instrumentation attribute with the given list of instrumentors to the class file.
159 * @param cf class file
160 * @param itors list of instrumentors
161 */
162 public static void addInstrumentationAttributeInfo(ClassFile cf, List<IInstrumentationStrategy> itors) {
163 StringBuilder sb = new StringBuilder();
164 for(IInstrumentationStrategy itor : itors) {
165 sb.append(';');
166 sb.append(itor.getClass().getName());
167 }
168 String s = sb.toString();
169 if (s.length()>0) {
170 s = s.substring(1);
171 }
172 addInstrumentationAttributeInfo(cf, s);
173 }
174
175 /**
176 * Add the Instrumentation attribute with the given list of instrumentors to the class file.
177 * @param cf class file
178 * @param itors collection of instrumentor class names
179 */
180 public static void addInstrumentationAttributeInfo(ClassFile cf, Collection<String> itors) {
181 StringBuilder sb = new StringBuilder();
182 for(String itor : itors) {
183 sb.append(';');
184 sb.append(itor);
185 }
186 String s = sb.toString();
187 if (s.length()>0) {
188 s = s.substring(1);
189 }
190 addInstrumentationAttributeInfo(cf, s);
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 NAME;
200 }
201 }