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