1 30 31 42 43 package jbet; 44 import java.io.*; 45 import java.util.*; 46 47 public class MethodInfo extends MethodSignature { 48 49 public static String JbetLogFacility = "method"; 50 51 52 private int nameIndex; 53 private int descriptorIndex; 54 private Vector codeAttributes; 55 private Vector attributes; 56 private int [] exceptionInts; 57 58 59 60 public Vector attrHints; 61 62 63 public int maxStack; 64 public int maxLocals; 65 public Snippit code; 66 public Vector codeAttrHints; 67 public boolean invalid_limits = false; 68 69 70 public boolean synthetic, deprecated; 71 72 73 class CallInfo 74 { 75 InternSet calls; 76 77 public Iterator calls () 78 { 79 return calls.iterator(); 80 } 81 } 82 83 Object block; 84 boolean[] lvused; 85 Object dataflow; public ClassInfo cr; 87 CallInfo calls; 88 89 void relocate (Hashtable subs) { 90 descriptor = descriptor.relocate_new(subs); 91 for (int i = 0; i < exceptions.size(); i++) { 92 String s = exceptionAt(i); 93 s = Util.relocate(s, subs); 94 exceptions.setElementAt(s, i); 95 } 96 if (code != null) 97 code.relocate(subs); 98 } 99 100 public MethodInfo () { 101 exceptions = new Vector(); 102 attrHints = new Vector(); 103 codeAttrHints = new Vector(); 104 } 105 106 public Object classrep() { return cr; } 107 108 public MethodInfo resolve() throws ClassFileException { 109 return this; 110 } 111 112 String exceptionAt(int i) { 113 return (String ) exceptions.elementAt(i); } 114 115 116 public void disassemble(LineWriter out, String prefix) { 117 out.println (prefix + ".method " + Util.flags2str(accessFlags) + " " + name + 118 " " + descriptor + " {"); 119 String p = prefix + " "; 120 for (int i = 0; i < exceptions.size(); i++) 121 out.println(p + ".throws " + exceptions.elementAt(i)); 122 if (synthetic) 123 out.println(p + ".synthetic"); 124 if (deprecated) 125 out.println(p + ".deprecated"); 126 if (code != null) { 127 out.println(p + ".maxstack " + maxStack); 128 out.println(p + ".maxlocals " + maxLocals); 129 code.disassemble(out, p); 130 } 131 out.println(prefix + "}"); 132 return; 133 } 134 135 public boolean checkAccess (String fromPackage) { 136 if ((accessFlags & ACC_PUBLIC) != 0) 137 return true; 138 if ((accessFlags & ACC_PRIVATE) != 0) 139 return false; 140 if ((accessFlags & ACC_PROTECTED) != 0) 141 return false; 142 return fromPackage.equals (cr.getPackageName()); 143 } 144 145 public boolean checkAccess (ClassInfo cr2) throws ClassFileException { 146 if ((accessFlags & ACC_PUBLIC) != 0) 147 return true; 148 if ((accessFlags & ACC_PRIVATE) != 0) 149 return false; 150 if ((accessFlags & ACC_PROTECTED) != 0) { 151 while (true) { 152 if (cr2 == cr) 153 return true; 154 if (cr2.superClass == null) 155 return false; 156 cr2 = Jbet.loader.getClass (cr2.superClass); 157 } 158 } 159 return cr2.getPackageName().equals (cr.getPackageName ()); 160 } 161 162 163 public MethodInfo (Lexer lexer) throws ClassFileException { 164 this(); 165 invalid_limits = true; 166 maxStack = -1; maxLocals = -1; 167 168 lexer.push(Lexer.ST_ASM); 169 if (!lexer.match(Token.TAG).text.equals(".method")) 170 lexer.unexpected(lexer.justread()); 171 accessFlags = lexer.parse_flags(ACC_ALL_MFLAGS); 172 name = lexer.match(Token.TAG).text; 173 descriptor = lexer.parse_descriptor(); 174 lexer.match('{'); 175 code = new Snippit(); 176 code.assemble(lexer, null, 0, this); 177 if (code.empty()) code = null; 178 lexer.match('}'); 179 lexer.pop(); 180 if (maxStack >= 0 && maxLocals >= 0) { 181 invalid_limits = false; 182 } 183 } 184 185 186 187 public MethodInfo (String n, Descriptor d, int acc) { 188 accessFlags = acc; 189 name = n; 190 descriptor = d; 191 exceptions = new Vector(); 192 attrHints = new Vector(); 193 maxStack = maxLocals = -1; 194 code = null; 195 synthetic = deprecated = false; 196 codeAttrHints = new Vector(); 197 } 198 199 public MethodInfo (String n, Descriptor d) { this (n,d,0); } 200 201 202 public MethodInfo (MethodInfo mi) { 203 name = mi.name; 204 accessFlags = mi.accessFlags; 205 descriptor = mi.descriptor; 206 207 exceptions = new Vector( mi.exceptions.size() ); 208 for (int i = 0; i < mi.exceptions.size(); i++) 209 exceptions.addElement( mi.exceptions.elementAt(i) ); 210 211 attrHints = new Vector(); 212 213 synthetic = mi.synthetic; 214 deprecated = mi.deprecated; 215 216 if (mi.code != null) { 217 maxStack = mi.maxStack; 218 maxLocals = mi.maxLocals; 219 code = new Snippit( mi.code ); 220 codeAttrHints = new Vector(); 221 } 222 cr = mi.cr; 223 } 224 225 226 void readCode (DataInputStream dataIn, ConstantPool constantPool) 227 throws IOException, ClassFileException { 228 229 maxStack = dataIn.readUnsignedShort(); 230 maxLocals = dataIn.readUnsignedShort(); 231 232 int codeLength = dataIn.readInt(); 233 234 235 byte [] bytes = new byte [ codeLength ] ; 236 dataIn.readFully (bytes, 0, codeLength); 237 238 int exTableLength = dataIn.readUnsignedShort(); 239 ExceptionRec [] exTable = new ExceptionRec [ exTableLength ]; 240 for (int i = 0; i < exTableLength; i++) 241 exTable[i] = new ExceptionRec (dataIn, constantPool); 242 243 LineNumRec [] lineNums = null; 244 LocalVarRec [] localVars = null; 245 246 code = new Snippit (bytes, exTable, constantPool); 247 248 int attributesCount = dataIn.readUnsignedShort(); 249 codeAttrHints = new Vector (attributesCount); 250 for (int i = 0; i < attributesCount; i++) { 251 int attrNameindex = dataIn.readUnsignedShort(); 252 String attrname = constantPool.utf8At(attrNameindex); 253 int length = dataIn.readInt(); 254 255 GenericAttribute item = new GenericAttribute (attrname, attrNameindex); 256 257 if (attrname.equals("LineNumberTable")) { 258 int numLines = dataIn.readUnsignedShort(); 259 lineNums = new LineNumRec [ numLines ]; 260 for (int j = 0; j < numLines; j++) 261 lineNums[j] = new LineNumRec (dataIn); 262 code.addLines( lineNums ); 263 item.writer = code.lineNumWriter(); 264 } else if (attrname.equals("LocalVariableTable")) { 265 int numLocals = dataIn.readUnsignedShort(); 266 localVars = new LocalVarRec [ numLocals ] ; 267 for (int j = 0; j < numLocals; j++) 268 localVars[j] = new LocalVarRec (dataIn, constantPool); 269 code.addLocals(localVars, constantPool); 270 item.writer = code.localsWriter(); 271 } else { 272 Jbet.warn.println ("Warning: unrecognised code attribute " + attrname); 273 item.read (length, dataIn); 274 } 275 codeAttrHints.addElement(item); 276 } 277 codeAttributes = codeAttrHints; 278 } 279 280 281 282 public MethodInfo (DataInputStream dataIn, ConstantPool constantPool) 283 throws IOException, ClassFileException { 284 Jbet.debug.print("reading method ... "); 285 exceptions = new Vector(); 286 synthetic = deprecated = false; 287 code = null; 288 codeAttributes = null; 289 290 accessFlags = dataIn.readUnsignedShort(); 291 292 nameIndex = dataIn.readUnsignedShort(); 293 name = constantPool.utf8At(nameIndex); 294 Jbet.debug.println(name); 295 296 descriptorIndex = dataIn.readUnsignedShort(); 297 String descriptorString = constantPool.utf8At(descriptorIndex); 298 descriptor = new Descriptor (descriptorString); 299 300 int attributesCount = dataIn.readUnsignedShort(); 301 attrHints = new Vector (attributesCount); 302 for (int i = 0; i < attributesCount; i++) { 303 int attrNameindex = dataIn.readUnsignedShort(); 304 String attrname = constantPool.utf8At(attrNameindex); 305 int length = dataIn.readInt(); 306 307 GenericAttribute item = new GenericAttribute (attrname, attrNameindex); 308 309 if (attrname.equals("Code")) { 310 readCode (dataIn, constantPool); 311 item.writer = codeWriter(); 312 } else if (attrname.equals("Exceptions")) { 313 int numExceptions = dataIn.readUnsignedShort(); 314 exceptionInts = new int [ numExceptions ]; 315 exceptions.ensureCapacity(numExceptions + exceptions.size()); 316 for (int j = 0; j < numExceptions; j++) { 317 int exclassIndex = dataIn.readUnsignedShort(); 318 exceptionInts[j] = exclassIndex; 319 exceptions.addElement( constantPool.cpClassAt(exclassIndex).string() ); 320 } 321 item.writer = exceptionsWriter(); 322 } else if (attrname.equals("Synthetic")) { 323 synthetic = true; 324 item.nodata(); 325 } else if (attrname.equals("Deprecated")) { 326 deprecated = true; 327 item.nodata(); 328 } else { 329 Jbet.warn.println ("Warning: unrecognised method attribute " + attrname); 330 item.read (length, dataIn); 331 } 332 attrHints.addElement(item); 333 } 334 attributes = attrHints; 335 336 } 337 338 public void resolveConstants () { 339 resolveConstants(cr.constantPool); 340 } 341 342 void resolveConstants (ConstantPool constantPool) { 343 if (invalid_limits) { 344 int ms = maxStack; 345 int ml = maxLocals; 346 try { 347 maxStack = maxLocals = -1; 348 DataFlow df = new DataFlow (this); 349 df.out = Jbet.debug; 350 df.run(true); 351 maxStack = df.maxStackDetected; 352 maxLocals = df.maxLocalsDetected; 353 invalid_limits = false; 354 } catch (Throwable e) { 355 maxStack = ms; 356 maxLocals = ml; 357 Jbet.warn.println ("Warning: caught a exception in resolve constants: " + e); 358 e.printStackTrace(Jbet.warn); 359 } 360 } 361 362 363 nameIndex = constantPool.internUtf8 (name); 364 descriptorIndex = constantPool.internUtf8( descriptor.toString() ); 365 366 Vector outAttrs = new Vector(); 367 368 if (synthetic) 369 outAttrs.addElement(new GenericAttribute("Synthetic", constantPool).nodata()); 370 371 if (deprecated) 372 outAttrs.addElement(new GenericAttribute("Deprecated", constantPool).nodata()); 373 374 if (exceptions.size() != 0) { 375 exceptionInts = new int [ exceptions.size() ]; 376 for (int i = 0; i < exceptions.size(); i++) 377 exceptionInts[i] = constantPool.internClass(exceptionAt(i)); 378 379 GenericAttribute attr = new GenericAttribute("Exceptions", constantPool); 380 attr.writer = exceptionsWriter(); 381 outAttrs.addElement( attr ); 382 } 383 384 if (code != null) 385 outAttrs.addElement( genCodeAttribute(constantPool) ); 386 387 attributes = new Vector( outAttrs.size() ); 388 389 GenericAttribute.permute(attrHints, outAttrs, attributes); 390 } 391 392 393 AttributeWriter exceptionsWriter() { 394 return new AttributeWriter() { 395 public void write(DataOutputStream dataOut) 396 throws IOException { 397 398 dataOut.writeShort(exceptionInts.length); 399 for (int i = 0; i < exceptionInts.length; i++) 400 dataOut.writeShort( exceptionInts[i] ); 401 } 402 public int size() { return 2 + exceptionInts.length*2; }; 403 }; 404 } 405 406 407 AttributeWriter codeWriter() { 408 return new AttributeWriter() { 409 public void write (DataOutputStream dataOut) 410 throws IOException, RuntimeException { 411 412 dataOut.writeShort (maxStack); 413 dataOut.writeShort (maxLocals); 414 code.writeCodeAndExceptions (dataOut); 415 416 dataOut.writeShort ( codeAttributes.size() ); 417 for (int i = 0; i < codeAttributes.size(); i++) 418 ((GenericAttribute)codeAttributes.elementAt(i)).writeAll(dataOut); 419 } 420 421 public int size() { 422 int ret = 2 + 2 + code.codeSize() + code.exceptionsSize() + 2; 423 for (int i = 0; i < codeAttributes.size(); i++) 424 ret += ((GenericAttribute)codeAttributes.elementAt(i)) 425 .writer.size() + 6; 426 return ret; 427 } 428 }; 429 } 430 431 GenericAttribute genCodeAttribute(ConstantPool constantPool) { 432 code.resolveConstants (constantPool); 433 Vector outAttrs = new Vector (); 434 435 GenericAttribute attr; 436 437 if ( (attr = code.genLineNumAttr(constantPool)) != null ) 438 outAttrs.addElement(attr); 439 if ( (attr = code.genLocalsAttr(constantPool)) != null ) 440 outAttrs.addElement(attr); 441 442 codeAttributes = new Vector ( outAttrs.size() ); 443 GenericAttribute.permute(codeAttrHints, outAttrs, codeAttributes); 444 445 attr = new GenericAttribute ("Code", constantPool); 446 attr.writer = codeWriter(); 447 448 return attr; 449 } 450 451 452 void writeFile (DataOutputStream dataOut) throws IOException { 453 454 dataOut.writeShort (accessFlags); 455 dataOut.writeShort (nameIndex); 456 dataOut.writeShort (descriptorIndex); 457 458 dataOut.writeShort( attributes.size() ); 459 for (int i = 0; i < attributes.size(); i++) 460 ((GenericAttribute)attributes.elementAt(i)).writeAll(dataOut); 461 } 462 463 public void removeDataFlow () 464 { 465 dataflow = null; 466 for (Instruction instr = code.head; instr != null; instr = instr.next) 467 instr._procState = null; 468 469 System.gc(); 470 } 471 472 public void printout(LineWriter out, boolean summarize) { 473 printout (out, summarize, false, false, false); 474 } 475 476 public void printout(LineWriter out, boolean summarize, boolean printlines, boolean printlocals, boolean printcounts) { 477 String f = flags2str(accessFlags); 478 if (!f.equals("")) 479 out.print( f + " " ); 480 481 if (synthetic) 482 out.print( "synthetic " ); 483 if (deprecated) 484 out.print( "deprecated " ); 485 486 out.print (name + " " + descriptor.toString() + (summarize ? "" : "\n")); 487 488 if (exceptions.size() != 0) { 489 out.print ( summarize ? " throws " : "\tThrows: "); 490 for (int i = 0; i < exceptions.size(); i++) 491 out.print ( exceptionAt(i) + " " ); 492 out.print( summarize ? "" : "\n" ); 493 } 494 495 if (summarize) { 496 out.println(); 497 return; 498 } 499 500 if (attributes == null || attributes.size() == 0) 501 return; 502 503 out.print( "\tAttributes:" ); 504 for (int i = 0; i < attributes.size(); i++) 505 out.print (" " + ((GenericAttribute)attributes.elementAt(i)).name ); 506 out.println(); 507 508 if (code == null) 509 return; 510 511 out.print( "\tCode Attributes:" ); 512 for (int i = 0; i < codeAttributes.size(); i++) 513 out.print (" " + ((GenericAttribute)codeAttributes.elementAt(i)).name); 514 out.println(); 515 516 517 out.println("\tCode Length: " + code.codelength); 518 out.println("\tMaxStack/MaxLocals: " + maxStack + "/" + maxLocals); 519 520 code.printExceptions(out); 521 if (printlocals) code.printLocals(out); 522 if (printlines) code.printLines(out); 523 code.printCode(out, true, printcounts); 524 525 } 526 527 static String flags2str (int accessFlags) { 528 return Util.flags2str(accessFlags); 529 } 530 531 public boolean isStatic() { 532 return (accessFlags & ACC_STATIC) != 0; 533 } 534 535 public boolean isVirtual() { 536 return (accessFlags & ACC_STATIC) == 0; 537 } 538 539 public boolean isNative() { 540 return (accessFlags & ACC_NATIVE) != 0; 541 } 542 543 void addDummyLocals () throws ClassFileException, DataFlowException { 544 code.resolveConstants (cr.constantPool); 545 DataFlow tr = new DataFlow (this); 546 tr.run(); 547 code.lvVector = new Vector(); 548 549 for (Instruction ins = code.head; ins != null; ins = ins.next) { 550 DataFlow.ProcState ps = (DataFlow.ProcState) ins.procState(); 551 552 if (ps == null) 553 continue; 554 for (int i = 0; i < ps.locals.length; i++) 555 if (ps.locals[i] != null && 556 ps.locals[i].base != 'l') { 557 LocalVarRec lv = new LocalVarRec(); 558 lv.name = "v" + i; 559 lv.descriptor = ps.locals[i]; 560 lv.index = i; 561 lv.start = new BranchTarget (ins); 562 lv.start.offset = ins.pc(); 563 lv.end = new BranchTarget (ins); 564 lv.length = 1; 565 code.lvVector.addElement (lv); 566 } 567 } 568 resolveConstants (); 569 } 570 571 public void addLinesAsPCs () 572 { 573 code.addLinesAsPCs (cr.constantPool); 574 } 575 576 public static final int ACC_PUBLIC = Util.ACC_PUBLIC; 577 public static final int ACC_PRIVATE = Util.ACC_PRIVATE; 578 public static final int ACC_PROTECTED = Util.ACC_PROTECTED; 579 public static final int ACC_STATIC = Util.ACC_STATIC; 580 public static final int ACC_FINAL = Util.ACC_FINAL; 581 public static final int ACC_SYNCHRONIZED = Util.ACC_SYNCHRONIZED; 582 public static final int ACC_NATIVE = Util.ACC_NATIVE; 583 public static final int ACC_ABSTRACT = Util.ACC_ABSTRACT; 584 public static final int ACC_STRICT = Util.ACC_STRICT; 585 586 public static final int ACC_ALL_MFLAGS = ACC_PUBLIC | ACC_PRIVATE | 587 ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | 588 ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT; 589 590 public boolean equals(Object o) { 591 return this == o; 592 } 593 594 public String qualifiedName() { 595 return cr.name() + "." + name + " : " + descriptor; 596 } 597 598 599 public boolean calls (MethodInfo other) { 600 if (calls == null) 601 findCalls (); 602 603 return calls.calls.contains (other); 604 } 605 606 607 public boolean icalls (MethodInfo other) { 608 return icalls1 (other, new InternSet ()); 609 } 610 611 612 public boolean recursive () { 613 return icalls1 (this, new InternSet ()); 614 } 615 616 private boolean icalls1 (MethodInfo other, InternSet done) { 617 if (calls == null) 618 findCalls (); 619 620 for (Iterator i = calls.calls(); i.hasNext(); ) { 621 MethodInfo mi = (MethodInfo) i.next(); 622 623 if (mi == other) 624 return true; 625 626 if (!done.contains (mi)) { 627 done.add (mi); 628 if (icalls1 (mi, done)) 629 return true; 630 } 631 } 632 633 return false; 634 } 635 636 public InternSet allCalls () { 637 return allCalls1 (new InternSet(), new InternSet ()); 638 } 639 640 InternSet allCalls1 (final InternSet out, final InternSet done) { 641 if (calls == null) 642 findCalls (); 643 644 for (Iterator i = calls.calls(); i.hasNext(); ) { 645 MethodInfo mi = (MethodInfo) i.next(); 646 647 if (!done.contains (mi)) { 648 done.add (mi); 649 mi.allCalls1 (out, done); 650 } 651 } 652 653 return out; 654 } 655 656 public void printCalls (LineWriter out) { 657 printCalls1 (out, new InternSet(), ""); 658 } 659 660 void printCalls1 (LineWriter out, InternSet done, String indent0) { 661 out.println (indent0 + cr.name() + '.' + name + descriptor); 662 String indent1 = indent0 + " "; 663 664 if (calls == null) 665 findCalls (); 666 667 for (Iterator i = calls.calls(); i.hasNext(); ) { 668 MethodSignature ms = (MethodSignature) i.next(); 669 try { 670 MethodInfo mi = ms.resolve(); 671 672 if (!done.contains (mi)) { 673 done.add (mi); 674 mi.printCalls1 (out, done, indent1); 675 } 676 else 677 out.println (indent1 + mi.cr.name() + '.' + mi.name + mi.descriptor); 678 } catch (Exception e) { 679 out.println (indent1 + ms.classrep() + '.' + ms.name + ms.descriptor + " E"); 680 } 681 } 682 } 683 684 685 void findCalls () { 686 calls = new CallInfo(); 687 calls.calls = new InternSet(); 688 689 if (code == null) 690 return; 691 692 for (Instruction ins = code.head; ins != null; ins = ins.next) { 693 if (ins.usesMethod ()) { 694 try { 695 MethodInfo mi = Jbet.loader.getMethod (ins.classRef(), ins.elemName(), ins.descriptor()); 696 calls.calls.add (mi); 697 } catch (ClassFileException e) { 698 calls.calls.add (new MethodSignature (ins.classRef(), ins.elemName(), ins.descriptor())); 699 } catch (ElementNotFoundException e) { 700 calls.calls.add (new MethodSignature (ins.classRef(), ins.elemName(), ins.descriptor())); 701 } 702 } 703 } 704 } 705 706 private boolean isOverridden (ClassInfo base) throws ClassFileException 707 { 708 if (base.superClass != null) { 709 ClassInfo suc = Jbet.loader.getClass (base.superClass); 710 if (suc.findMethod (name, descriptor) != null) 711 return true; 712 if (isOverridden (suc)) 713 return true; 714 } 715 716 for (int i = 0; i < base.interfaces.size(); i++) { 717 ClassInfo ic = Jbet.loader.getClass (base.interfaceAt (i)); 718 if (ic.findMethod (name, descriptor) != null) 719 return true; 720 if (isOverridden (ic)) 721 return true; 722 } 723 724 return false; 725 } 726 727 public boolean isOverridden () throws ClassFileException 728 { 729 return isOverridden (cr); 730 } 731 } 732 | Popular Tags |