1 17 package org.apache.bcel.util; 18 19 import java.io.FileOutputStream ; 20 import java.io.IOException ; 21 import java.io.PrintWriter ; 22 import java.util.BitSet ; 23 import org.apache.bcel.classfile.Attribute; 24 import org.apache.bcel.classfile.Code; 25 import org.apache.bcel.classfile.CodeException; 26 import org.apache.bcel.classfile.ConstantFieldref; 27 import org.apache.bcel.classfile.ConstantInterfaceMethodref; 28 import org.apache.bcel.classfile.ConstantMethodref; 29 import org.apache.bcel.classfile.ConstantNameAndType; 30 import org.apache.bcel.classfile.ConstantPool; 31 import org.apache.bcel.classfile.LocalVariable; 32 import org.apache.bcel.classfile.LocalVariableTable; 33 import org.apache.bcel.classfile.Method; 34 import org.apache.bcel.classfile.Utility; 35 36 43 final class CodeHTML implements org.apache.bcel.Constants { 44 45 private String class_name; private Method[] methods; private PrintWriter file; private BitSet goto_set; 49 private ConstantPool constant_pool; 50 private ConstantHTML constant_html; 51 private static boolean wide = false; 52 53 54 CodeHTML(String dir, String class_name, Method[] methods, ConstantPool constant_pool, 55 ConstantHTML constant_html) throws IOException { 56 this.class_name = class_name; 57 this.methods = methods; 58 this.constant_pool = constant_pool; 59 this.constant_html = constant_html; 60 file = new PrintWriter (new FileOutputStream (dir + class_name + "_code.html")); 61 file.println("<HTML><BODY BGCOLOR=\"#C0C0C0\">"); 62 for (int i = 0; i < methods.length; i++) { 63 writeMethod(methods[i], i); 64 } 65 file.println("</BODY></HTML>"); 66 file.close(); 67 } 68 69 70 77 private final String codeToHTML( ByteSequence bytes, int method_number ) throws IOException { 78 short opcode = (short) bytes.readUnsignedByte(); 79 StringBuffer buf; 80 String name, signature; 81 int default_offset = 0, low, high; 82 int index, class_index, vindex, constant; 83 int[] jump_table; 84 int no_pad_bytes = 0, offset; 85 buf = new StringBuffer (256); 86 buf.append("<TT>").append(OPCODE_NAMES[opcode]).append("</TT></TD><TD>"); 87 90 if ((opcode == TABLESWITCH) || (opcode == LOOKUPSWITCH)) { 91 int remainder = bytes.getIndex() % 4; 92 no_pad_bytes = (remainder == 0) ? 0 : 4 - remainder; 93 for (int i = 0; i < no_pad_bytes; i++) { 94 bytes.readByte(); 95 } 96 default_offset = bytes.readInt(); 98 } 99 switch (opcode) { 100 case TABLESWITCH: 101 low = bytes.readInt(); 102 high = bytes.readInt(); 103 offset = bytes.getIndex() - 12 - no_pad_bytes - 1; 104 default_offset += offset; 105 buf.append("<TABLE BORDER=1><TR>"); 106 jump_table = new int[high - low + 1]; 108 for (int i = 0; i < jump_table.length; i++) { 109 jump_table[i] = offset + bytes.readInt(); 110 buf.append("<TH>").append(low + i).append("</TH>"); 111 } 112 buf.append("<TH>default</TH></TR>\n<TR>"); 113 for (int i = 0; i < jump_table.length; i++) { 115 buf.append("<TD><A HREF=\"#code").append(method_number).append("@").append( 116 jump_table[i]).append("\">").append(jump_table[i]).append("</A></TD>"); 117 } 118 buf.append("<TD><A HREF=\"#code").append(method_number).append("@").append( 119 default_offset).append("\">").append(default_offset).append( 120 "</A></TD></TR>\n</TABLE>\n"); 121 break; 122 124 case LOOKUPSWITCH: 125 int npairs = bytes.readInt(); 126 offset = bytes.getIndex() - 8 - no_pad_bytes - 1; 127 jump_table = new int[npairs]; 128 default_offset += offset; 129 buf.append("<TABLE BORDER=1><TR>"); 130 for (int i = 0; i < npairs; i++) { 132 int match = bytes.readInt(); 133 jump_table[i] = offset + bytes.readInt(); 134 buf.append("<TH>").append(match).append("</TH>"); 135 } 136 buf.append("<TH>default</TH></TR>\n<TR>"); 137 for (int i = 0; i < npairs; i++) { 139 buf.append("<TD><A HREF=\"#code").append(method_number).append("@").append( 140 jump_table[i]).append("\">").append(jump_table[i]).append("</A></TD>"); 141 } 142 buf.append("<TD><A HREF=\"#code").append(method_number).append("@").append( 143 default_offset).append("\">").append(default_offset).append( 144 "</A></TD></TR>\n</TABLE>\n"); 145 break; 146 149 case GOTO: 150 case IFEQ: 151 case IFGE: 152 case IFGT: 153 case IFLE: 154 case IFLT: 155 case IFNE: 156 case IFNONNULL: 157 case IFNULL: 158 case IF_ACMPEQ: 159 case IF_ACMPNE: 160 case IF_ICMPEQ: 161 case IF_ICMPGE: 162 case IF_ICMPGT: 163 case IF_ICMPLE: 164 case IF_ICMPLT: 165 case IF_ICMPNE: 166 case JSR: 167 index = (int) (bytes.getIndex() + bytes.readShort() - 1); 168 buf.append("<A HREF=\"#code").append(method_number).append("@").append(index) 169 .append("\">").append(index).append("</A>"); 170 break; 171 173 case GOTO_W: 174 case JSR_W: 175 int windex = bytes.getIndex() + bytes.readInt() - 1; 176 buf.append("<A HREF=\"#code").append(method_number).append("@").append(windex) 177 .append("\">").append(windex).append("</A>"); 178 break; 179 181 case ALOAD: 182 case ASTORE: 183 case DLOAD: 184 case DSTORE: 185 case FLOAD: 186 case FSTORE: 187 case ILOAD: 188 case ISTORE: 189 case LLOAD: 190 case LSTORE: 191 case RET: 192 if (wide) { 193 vindex = bytes.readShort(); 194 wide = false; } else { 196 vindex = bytes.readUnsignedByte(); 197 } 198 buf.append("%").append(vindex); 199 break; 200 205 case WIDE: 206 wide = true; 207 buf.append("(wide)"); 208 break; 209 211 case NEWARRAY: 212 buf.append("<FONT COLOR=\"#00FF00\">").append(TYPE_NAMES[bytes.readByte()]).append( 213 "</FONT>"); 214 break; 215 217 case GETFIELD: 218 case GETSTATIC: 219 case PUTFIELD: 220 case PUTSTATIC: 221 index = bytes.readShort(); 222 ConstantFieldref c1 = (ConstantFieldref) constant_pool.getConstant(index, 223 CONSTANT_Fieldref); 224 class_index = c1.getClassIndex(); 225 name = constant_pool.getConstantString(class_index, CONSTANT_Class); 226 name = Utility.compactClassName(name, false); 227 index = c1.getNameAndTypeIndex(); 228 String field_name = constant_pool.constantToString(index, CONSTANT_NameAndType); 229 if (name.equals(class_name)) { buf.append("<A HREF=\"").append(class_name).append("_methods.html#field") 231 .append(field_name).append("\" TARGET=Methods>").append(field_name) 232 .append("</A>\n"); 233 } else { 234 buf.append(constant_html.referenceConstant(class_index)).append(".").append( 235 field_name); 236 } 237 break; 238 240 case CHECKCAST: 241 case INSTANCEOF: 242 case NEW: 243 index = bytes.readShort(); 244 buf.append(constant_html.referenceConstant(index)); 245 break; 246 248 case INVOKESPECIAL: 249 case INVOKESTATIC: 250 case INVOKEVIRTUAL: 251 case INVOKEINTERFACE: 252 int m_index = bytes.readShort(); 253 String str; 254 if (opcode == INVOKEINTERFACE) { int nargs = bytes.readUnsignedByte(); int reserved = bytes.readUnsignedByte(); ConstantInterfaceMethodref c = (ConstantInterfaceMethodref) constant_pool 258 .getConstant(m_index, CONSTANT_InterfaceMethodref); 259 class_index = c.getClassIndex(); 260 str = constant_pool.constantToString(c); 261 index = c.getNameAndTypeIndex(); 262 } else { 263 ConstantMethodref c = (ConstantMethodref) constant_pool.getConstant(m_index, 264 CONSTANT_Methodref); 265 class_index = c.getClassIndex(); 266 str = constant_pool.constantToString(c); 267 index = c.getNameAndTypeIndex(); 268 } 269 name = Class2HTML.referenceClass(class_index); 270 str = Class2HTML.toHTML(constant_pool.constantToString(constant_pool.getConstant( 271 index, CONSTANT_NameAndType))); 272 ConstantNameAndType c2 = (ConstantNameAndType) constant_pool.getConstant(index, 274 CONSTANT_NameAndType); 275 signature = constant_pool.constantToString(c2.getSignatureIndex(), CONSTANT_Utf8); 276 String [] args = Utility.methodSignatureArgumentTypes(signature, false); 277 String type = Utility.methodSignatureReturnType(signature, false); 278 buf.append(name).append(".<A HREF=\"").append(class_name).append("_cp.html#cp") 279 .append(m_index).append("\" TARGET=ConstantPool>").append(str).append( 280 "</A>").append("("); 281 for (int i = 0; i < args.length; i++) { 283 buf.append(Class2HTML.referenceType(args[i])); 284 if (i < args.length - 1) { 285 buf.append(", "); 286 } 287 } 288 buf.append("):").append(Class2HTML.referenceType(type)); 290 break; 291 293 case LDC_W: 294 case LDC2_W: 295 index = bytes.readShort(); 296 buf.append("<A HREF=\"").append(class_name).append("_cp.html#cp").append(index) 297 .append("\" TARGET=\"ConstantPool\">").append( 298 Class2HTML.toHTML(constant_pool.constantToString(index, 299 constant_pool.getConstant(index).getTag()))).append("</a>"); 300 break; 301 case LDC: 302 index = bytes.readUnsignedByte(); 303 buf.append("<A HREF=\"").append(class_name).append("_cp.html#cp").append(index) 304 .append("\" TARGET=\"ConstantPool\">").append( 305 Class2HTML.toHTML(constant_pool.constantToString(index, 306 constant_pool.getConstant(index).getTag()))).append("</a>"); 307 break; 308 310 case ANEWARRAY: 311 index = bytes.readShort(); 312 buf.append(constant_html.referenceConstant(index)); 313 break; 314 316 case MULTIANEWARRAY: 317 index = bytes.readShort(); 318 int dimensions = bytes.readByte(); 319 buf.append(constant_html.referenceConstant(index)).append(":").append(dimensions) 320 .append("-dimensional"); 321 break; 322 324 case IINC: 325 if (wide) { 326 vindex = bytes.readShort(); 327 constant = bytes.readShort(); 328 wide = false; 329 } else { 330 vindex = bytes.readUnsignedByte(); 331 constant = bytes.readByte(); 332 } 333 buf.append("%").append(vindex).append(" ").append(constant); 334 break; 335 default: 336 if (NO_OF_OPERANDS[opcode] > 0) { 337 for (int i = 0; i < TYPE_OF_OPERANDS[opcode].length; i++) { 338 switch (TYPE_OF_OPERANDS[opcode][i]) { 339 case T_BYTE: 340 buf.append(bytes.readUnsignedByte()); 341 break; 342 case T_SHORT: buf.append(bytes.readShort()); 344 break; 345 case T_INT: 346 buf.append(bytes.readInt()); 347 break; 348 default: System.err.println("Unreachable default case reached!"); 350 System.exit(-1); 351 } 352 buf.append(" "); 353 } 354 } 355 } 356 buf.append("</TD>"); 357 return buf.toString(); 358 } 359 360 361 365 private final void findGotos( ByteSequence bytes, Method method, Code code ) throws IOException { 366 int index; 367 goto_set = new BitSet (bytes.available()); 368 int opcode; 369 372 if (code != null) { 373 CodeException[] ce = code.getExceptionTable(); 374 int len = ce.length; 375 for (int i = 0; i < len; i++) { 376 goto_set.set(ce[i].getStartPC()); 377 goto_set.set(ce[i].getEndPC()); 378 goto_set.set(ce[i].getHandlerPC()); 379 } 380 Attribute[] attributes = code.getAttributes(); 382 for (int i = 0; i < attributes.length; i++) { 383 if (attributes[i].getTag() == ATTR_LOCAL_VARIABLE_TABLE) { 384 LocalVariable[] vars = ((LocalVariableTable) attributes[i]) 385 .getLocalVariableTable(); 386 for (int j = 0; j < vars.length; j++) { 387 int start = vars[j].getStartPC(); 388 int end = (int) (start + vars[j].getLength()); 389 goto_set.set(start); 390 goto_set.set(end); 391 } 392 break; 393 } 394 } 395 } 396 for (int i = 0; bytes.available() > 0; i++) { 398 opcode = bytes.readUnsignedByte(); 399 switch (opcode) { 401 case TABLESWITCH: 402 case LOOKUPSWITCH: 403 int remainder = bytes.getIndex() % 4; 405 int no_pad_bytes = (remainder == 0) ? 0 : 4 - remainder; 406 int default_offset, 407 offset; 408 for (int j = 0; j < no_pad_bytes; j++) { 409 bytes.readByte(); 410 } 411 default_offset = bytes.readInt(); 413 if (opcode == TABLESWITCH) { 414 int low = bytes.readInt(); 415 int high = bytes.readInt(); 416 offset = bytes.getIndex() - 12 - no_pad_bytes - 1; 417 default_offset += offset; 418 goto_set.set(default_offset); 419 for (int j = 0; j < (high - low + 1); j++) { 420 index = offset + bytes.readInt(); 421 goto_set.set(index); 422 } 423 } else { int npairs = bytes.readInt(); 425 offset = bytes.getIndex() - 8 - no_pad_bytes - 1; 426 default_offset += offset; 427 goto_set.set(default_offset); 428 for (int j = 0; j < npairs; j++) { 429 int match = bytes.readInt(); 430 index = offset + bytes.readInt(); 431 goto_set.set(index); 432 } 433 } 434 break; 435 case GOTO: 436 case IFEQ: 437 case IFGE: 438 case IFGT: 439 case IFLE: 440 case IFLT: 441 case IFNE: 442 case IFNONNULL: 443 case IFNULL: 444 case IF_ACMPEQ: 445 case IF_ACMPNE: 446 case IF_ICMPEQ: 447 case IF_ICMPGE: 448 case IF_ICMPGT: 449 case IF_ICMPLE: 450 case IF_ICMPLT: 451 case IF_ICMPNE: 452 case JSR: 453 index = bytes.getIndex() + bytes.readShort() - 1; 455 goto_set.set(index); 456 break; 457 case GOTO_W: 458 case JSR_W: 459 index = bytes.getIndex() + bytes.readInt() - 1; 461 goto_set.set(index); 462 break; 463 default: 464 bytes.unreadByte(); 465 codeToHTML(bytes, 0); } 467 } 468 } 469 470 471 474 private void writeMethod( Method method, int method_number ) throws IOException { 475 String signature = method.getSignature(); 477 String [] args = Utility.methodSignatureArgumentTypes(signature, false); 479 String type = Utility.methodSignatureReturnType(signature, false); 481 String name = method.getName(); 483 String html_name = Class2HTML.toHTML(name); 484 String access = Utility.accessToString(method.getAccessFlags()); 486 access = Utility.replace(access, " ", " "); 487 Attribute[] attributes = method.getAttributes(); 489 file.print("<P><B><FONT COLOR=\"#FF0000\">" + access + "</FONT> " + "<A NAME=method" 490 + method_number + ">" + Class2HTML.referenceType(type) + "</A> <A HREF=\"" 491 + class_name + "_methods.html#method" + method_number + "\" TARGET=Methods>" 492 + html_name + "</A>("); 493 for (int i = 0; i < args.length; i++) { 494 file.print(Class2HTML.referenceType(args[i])); 495 if (i < args.length - 1) { 496 file.print(", "); 497 } 498 } 499 file.println(")</B></P>"); 500 Code c = null; 501 byte[] code = null; 502 if (attributes.length > 0) { 503 file.print("<H4>Attributes</H4><UL>\n"); 504 for (int i = 0; i < attributes.length; i++) { 505 byte tag = attributes[i].getTag(); 506 if (tag != ATTR_UNKNOWN) { 507 file.print("<LI><A HREF=\"" + class_name + "_attributes.html#method" 508 + method_number + "@" + i + "\" TARGET=Attributes>" 509 + ATTRIBUTE_NAMES[tag] + "</A></LI>\n"); 510 } else { 511 file.print("<LI>" + attributes[i] + "</LI>"); 512 } 513 if (tag == ATTR_CODE) { 514 c = (Code) attributes[i]; 515 Attribute[] attributes2 = c.getAttributes(); 516 code = c.getCode(); 517 file.print("<UL>"); 518 for (int j = 0; j < attributes2.length; j++) { 519 tag = attributes2[j].getTag(); 520 file.print("<LI><A HREF=\"" + class_name + "_attributes.html#" + "method" 521 + method_number + "@" + i + "@" + j + "\" TARGET=Attributes>" 522 + ATTRIBUTE_NAMES[tag] + "</A></LI>\n"); 523 } 524 file.print("</UL>"); 525 } 526 } 527 file.println("</UL>"); 528 } 529 if (code != null) { ByteSequence stream = new ByteSequence(code); 533 stream.mark(stream.available()); 534 findGotos(stream, method, c); 535 stream.reset(); 536 file.println("<TABLE BORDER=0><TR><TH ALIGN=LEFT>Byte<BR>offset</TH>" 537 + "<TH ALIGN=LEFT>Instruction</TH><TH ALIGN=LEFT>Argument</TH>"); 538 for (int i = 0; stream.available() > 0; i++) { 539 int offset = stream.getIndex(); 540 String str = codeToHTML(stream, method_number); 541 String anchor = ""; 542 545 if (goto_set.get(offset)) { 546 anchor = "<A NAME=code" + method_number + "@" + offset + "></A>"; 547 } 548 String anchor2; 549 if (stream.getIndex() == code.length) { 550 anchor2 = "<A NAME=code" + method_number + "@" + code.length + ">" + offset 551 + "</A>"; 552 } else { 553 anchor2 = "" + offset; 554 } 555 file 556 .println("<TR VALIGN=TOP><TD>" + anchor2 + "</TD><TD>" + anchor + str 557 + "</TR>"); 558 } 559 file.println("<TR><TD> </A></TD></TR>"); 561 file.println("</TABLE>"); 562 } 563 } 564 } 565 | Popular Tags |