001 package sysModel.classFile; 002 003 import sysModel.classFile.attributes.AAttributeInfo; 004 import sysModel.classFile.attributes.CodeAttributeInfo; 005 import sysModel.classFile.attributes.visitors.ADefaultAttributeVisitor; 006 import sysModel.classFile.code.InstructionList; 007 import sysModel.classFile.constantPool.AUTFPoolInfo; 008 import sysModel.classFile.constantPool.ConstantPool; 009 import sysModel.classFile.constantPool.visitors.CheckUTFVisitor; 010 011 import java.io.DataInputStream; 012 import java.io.DataOutputStream; 013 import java.io.IOException; 014 import java.util.ArrayList; 015 016 /** 017 * Represents a method in a class file. 018 * 019 * @author Mathias Ricken 020 */ 021 022 public final class MethodInfo { 023 /** 024 * Method access flags. 025 */ 026 private short _accessFlags; 027 028 /** 029 * Name information. 030 */ 031 private AUTFPoolInfo _name; 032 033 /** 034 * Type descriptor information. 035 */ 036 private AUTFPoolInfo _descriptor; 037 038 /** 039 * Attributes. 040 */ 041 private ArrayList<AAttributeInfo> _attributes = new ArrayList<AAttributeInfo>(); 042 043 /** 044 * Constructor. 045 * 046 * @param accessFlags method access flags 047 * @param name method name 048 * @param signature method descriptor 049 * @param attributes array of attributes 050 */ 051 public MethodInfo(short accessFlags, 052 AUTFPoolInfo name, 053 AUTFPoolInfo signature, 054 AAttributeInfo[] attributes) { 055 _accessFlags = accessFlags; 056 _name = name; 057 _descriptor = signature; 058 if (null != attributes) { 059 for(AAttributeInfo attr : attributes) { 060 _attributes.add(attr); 061 } 062 } 063 } 064 065 /** 066 * Constructor. 067 * 068 * @param di input stream 069 * @param pool constant pool 070 * 071 * @throws IOException 072 * @throws ClassFormatError 073 */ 074 public MethodInfo(DataInputStream di, ConstantPool pool) throws IOException, ClassFormatError { 075 _accessFlags = di.readShort(); 076 _name = pool.get(di.readShort()).execute(CheckUTFVisitor.singleton(), null); 077 _descriptor = pool.get(di.readShort()).execute(CheckUTFVisitor.singleton(), null); 078 079 int count = di.readShort(); 080 for(int i = 0; i < count; i++) { 081 _attributes.add(AAttributeInfo.read(di, pool)); 082 } 083 } 084 085 /** 086 * Write this method into the stream. 087 * 088 * @param dos output stream 089 * @param pool constant pool 090 * 091 * @throws IOException 092 */ 093 public void write(DataOutputStream dos, ConstantPool pool) throws IOException { 094 dos.writeShort(_accessFlags); 095 dos.writeShort(pool.indexOf(_name)); 096 dos.writeShort(pool.indexOf(_descriptor)); 097 dos.writeShort(_attributes.size()); 098 for(AAttributeInfo attr : _attributes) { 099 attr.write(dos); 100 } 101 } 102 103 /** 104 * Return a human-readable version of this method. 105 * 106 * @return string 107 */ 108 public String toString() { 109 String s = _descriptor.toString(); 110 String paramSig = s.substring(s.indexOf('(') + 1, s.indexOf(')')); 111 String returnSig = s.substring(s.indexOf(')') + 1); 112 113 // handle constructor correctly 114 StringBuffer parameterList = new StringBuffer(); 115 parameterList.append(_name + "("); 116 117 char initialParameter = 'a'; 118 if ((0 < paramSig.length()) && 'V' != paramSig.charAt(0)) { 119 StringBuffer varName = new StringBuffer(); 120 while(0 < paramSig.length()) { 121 varName.setLength(0); 122 varName.append(initialParameter); 123 initialParameter++; 124 parameterList.append(ClassFileTools.getTypeString(paramSig, varName.toString())); 125 paramSig = ClassFileTools.getNextSignature(paramSig); 126 if (0 < paramSig.length()) { 127 parameterList.append(", "); 128 } 129 } 130 131 } 132 parameterList.append(')'); 133 134 StringBuffer x = new StringBuffer(); 135 x.append(ClassFileTools.getAccessString(_accessFlags)); 136 x.append(ClassFileTools.getTypeString(returnSig, parameterList.toString())); 137 138 return x.toString(); 139 } 140 141 /** 142 * Return a human-readable version of this method. 143 * 144 * @param pool constant pool 145 * 146 * @return string 147 */ 148 public String toString(ConstantPool pool) { 149 return toString(pool, true, true); 150 } 151 152 /** 153 * Return a human-readable version of this method. 154 * 155 * @param pool constant pool 156 * @param lineNumbers print line numbers 157 * @param PCs print PC values 158 * 159 * @return string 160 */ 161 public String toString(ConstantPool pool, boolean lineNumbers, boolean PCs) { 162 String s = _descriptor.toString(); 163 String paramSig = s.substring(s.indexOf('(') + 1, s.indexOf(')')); 164 String returnSig = s.substring(s.indexOf(')') + 1); 165 166 // handle constructor correctly 167 StringBuffer parameterList = new StringBuffer(); 168 parameterList.append(_name + "("); 169 170 char initialParameter = 'a'; 171 if ((0 < paramSig.length()) && 'V' != paramSig.charAt(0)) { 172 StringBuffer varName = new StringBuffer(); 173 while(0 < paramSig.length()) { 174 varName.setLength(0); 175 varName.append(initialParameter); 176 initialParameter++; 177 parameterList.append(ClassFileTools.getTypeString(paramSig, varName.toString())); 178 paramSig = ClassFileTools.getNextSignature(paramSig); 179 if (0 < paramSig.length()) { 180 parameterList.append(", "); 181 } 182 } 183 184 } 185 parameterList.append(')'); 186 187 StringBuffer x = new StringBuffer(); 188 x.append(ClassFileTools.getAccessString(_accessFlags)); 189 x.append(ClassFileTools.getTypeString(returnSig, parameterList.toString())); 190 191 for(AAttributeInfo attr : _attributes) { 192 x.append("\n\t").append(attr.toString()); 193 } 194 195 if (0 == (_accessFlags & (ClassFile.ACC_NATIVE | ClassFile.ACC_ABSTRACT))) { 196 CodeAttributeInfo ca = getCodeAttributeInfo(); 197 x.append('\n').append((new InstructionList(ca.getCode())).toString(lineNumbers, PCs)); 198 } 199 200 return x.toString(); 201 } 202 203 /** 204 * Accessor for access flags. 205 * 206 * @return access flags 207 */ 208 public short getAccessFlags() { 209 return _accessFlags; 210 } 211 212 /** 213 * Mutator for access flags. 214 * 215 * @param accessFlags new access flags 216 */ 217 public void setAccessFlags(short accessFlags) { 218 _accessFlags = accessFlags; 219 } 220 221 /** 222 * Accessor for field name. 223 * 224 * @return field name 225 */ 226 public AUTFPoolInfo getName() { 227 return _name; 228 } 229 230 /** 231 * Mutator for field name. 232 * 233 * @param name new field name 234 */ 235 public void setName(AUTFPoolInfo name) { 236 _name = name; 237 } 238 239 /** 240 * Accessor for descriptor. 241 * 242 * @return descriptor 243 */ 244 public AUTFPoolInfo getDescriptor() { 245 return _descriptor; 246 } 247 248 /** 249 * Mutator for descriptor. 250 * 251 * @param descriptor new descriptor 252 */ 253 public void setDescriptor(AUTFPoolInfo descriptor) { 254 _descriptor = descriptor; 255 } 256 257 /** 258 * Accessor for attributes. 259 * 260 * @return attributes 261 */ 262 public ArrayList<AAttributeInfo> getAttributes() { 263 return _attributes; 264 } 265 266 /** 267 * Return this method's code attribute info. 268 * 269 * @return code attribute info 270 */ 271 public CodeAttributeInfo getCodeAttributeInfo() { 272 ADefaultAttributeVisitor<CodeAttributeInfo, Object> getCodeAttributeVisitor 273 = new ADefaultAttributeVisitor<CodeAttributeInfo, Object>() { 274 public CodeAttributeInfo defaultCase(AAttributeInfo host, Object o) { 275 return null; 276 } 277 278 public CodeAttributeInfo codeCase(CodeAttributeInfo host, Object o) { 279 return host; 280 } 281 }; 282 for(AAttributeInfo attr : _attributes) { 283 CodeAttributeInfo code = attr.execute(getCodeAttributeVisitor, null); 284 if (null != code) { 285 return code; 286 } 287 288 } 289 throw new ClassFormatError("Method has no Code attribute"); 290 } 291 }