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 }