1 package gov.nasa.jpf.jvm; 20 21 import gov.nasa.jpf.JPFException; 22 import gov.nasa.jpf.jvm.bytecode.Instruction; 23 import gov.nasa.jpf.util.Debug; 24 25 import org.apache.bcel.Constants; 26 import org.apache.bcel.classfile.Code; 27 import org.apache.bcel.classfile.CodeException; 28 import org.apache.bcel.classfile.ConstantPool; 29 import org.apache.bcel.classfile.LineNumberTable; 30 import org.apache.bcel.classfile.LocalVariable; 31 import org.apache.bcel.classfile.LocalVariableTable; 32 import org.apache.bcel.classfile.Method; 33 import org.apache.bcel.generic.InstructionHandle; 34 import org.apache.bcel.generic.InstructionList; 35 import gov.nasa.jpf.jvm.bytecode.RETURN; 36 import gov.nasa.jpf.jvm.bytecode.InvokeInstruction; 37 import gov.nasa.jpf.jvm.bytecode.INVOKESTATIC; 38 import gov.nasa.jpf.jvm.bytecode.INVOKESPECIAL; 39 import gov.nasa.jpf.jvm.bytecode.INVOKEVIRTUAL; 40 41 42 46 public class MethodInfo implements Cloneable { 47 50 protected static boolean warnedLocalInfo = false; 51 static final int MJI_NONE = 0; 52 static final int MJI_NATIVE = 0x1; 53 static final int MJI_NONDETERMINISTIC = 0x2; 54 static final int MJI_COND_DETERMINISTIC = 0x4; 55 static final int MJI_COND_EXECUTABLE = 0x8; 56 57 60 public static final int SR_NEVER = 0; public static final int SR_ALWAYS = 0x1; public static final int SR_RUNNABLES = 0x2; public static final int SR_SYNC = 0x4; 65 public static final int SR_NEVERBODY = 0x8; 67 70 protected String name; 71 72 75 protected String signature; 76 77 80 protected ClassInfo ci; 81 82 85 protected Instruction[] code; 86 87 90 protected ExceptionHandler[] exceptions; 91 92 95 protected int[] lineNumbers; 96 97 100 protected String [] localVariableNames; 101 102 105 protected String [] localVariableTypes; 106 107 110 protected boolean isStatic; 111 112 115 protected boolean isSynchronized; 116 117 120 protected boolean isAtomic; 121 122 125 protected boolean isNative; 126 127 130 protected int schedulingRelevance; 131 132 135 protected int maxLocals; 136 137 140 protected int maxStack; 141 142 144 147 private int argSize = -1; 148 149 152 private int nArgs = -1; 153 154 157 private byte returnType = -1; 158 159 162 private byte[] argTypes = null; 163 164 167 int mjiAttrs = MJI_NONE; 168 169 173 private String uniqueName; 174 175 178 protected MethodInfo (Method m, ClassInfo c) { 179 name = m.getName(); 180 signature = m.getSignature(); 181 ci = c; 182 183 code = loadCode(m); 184 exceptions = loadExceptions(m); 185 lineNumbers = loadLineNumbers(m); 186 maxLocals = getMaxLocals(m); 187 maxStack = getMaxStack(m); 188 localVariableNames = loadLocalVariableNames(m); 189 localVariableTypes = loadLocalVariableTypes(m); 190 isStatic = m.isStatic(); 191 isSynchronized = m.isSynchronized(); 192 isNative = m.isNative(); 193 194 uniqueName = getUniqueName(name, signature); 197 } 198 199 void setAtomic (boolean isAtomic) { 200 this.isAtomic = isAtomic; 201 } 202 203 public boolean isAtomic () { 204 return isAtomic; 205 } 206 207 void setSchedulingRelevance (int sr) { 208 schedulingRelevance = sr; 209 } 210 211 public Object clone() { 212 try { 213 return super.clone(); 214 } catch (CloneNotSupportedException cnx) { 215 return null; 216 } 217 } 218 219 222 MethodInfo createNativeCallStub () { 223 MethodInfo mi = (MethodInfo) clone(); 224 String cname = ci.getName(); 225 InvokeInstruction insn; 226 227 if (isStatic) { 228 insn = new INVOKESTATIC(mi, cname, name, signature, 0, 0); 229 } else if (name.equals("<init>")){ 230 insn = new INVOKESPECIAL(mi, cname, name, signature, 0, 0); 231 } else { 232 insn = new INVOKEVIRTUAL(mi, cname, name, signature, 0, 0); 233 } 234 235 mi.code = new Instruction[2]; 236 mi.code[0] = insn; 237 mi.code[1] = new RETURN(mi, 1, 4); 238 239 mi.lineNumbers = null; 241 mi.exceptions = null; 242 243 return mi; 244 } 245 246 247 252 public static String getUniqueName (String mname, String signature) { 253 return (mname + signature.substring(0, signature.indexOf(')') + 1)); 254 } 255 256 public static MethodInfo newInstance (Method m, ClassInfo c) { 257 return (new MethodInfo(m, c)); 258 } 259 260 public static MethodInfo[] newInstanceArray (int length) { 261 return (new MethodInfo[length]); 262 } 263 264 public byte[] getArgumentTypes () { 265 if (argTypes == null) { 266 argTypes = Types.getArgumentTypes(signature); 267 } 268 269 return argTypes; 270 } 271 272 public int getArgumentsSize () { 273 if (argSize < 0) { 274 argSize = Types.getArgumentsSize(signature); 275 276 if (!isStatic) { 277 argSize++; 278 } 279 } 280 281 return argSize; 282 } 283 284 285 288 public ClassInfo getClassInfo () { 289 return ci; 290 } 291 292 295 public String getCompleteName () { 296 return ci.getName() + "." + name + signature; 297 } 298 299 public boolean isDeterministic (ThreadInfo ti) { 300 if ((mjiAttrs & MJI_COND_DETERMINISTIC) != 0) { 301 return ci.isMethodCondDeterministic(ti, this); 302 } else { 303 return ((mjiAttrs & MJI_NONDETERMINISTIC) == 0); 306 } 307 } 308 309 public boolean isExecutable (ThreadInfo ti) { 310 boolean canEnter = false; 311 312 if ((mjiAttrs & MJI_COND_EXECUTABLE) != 0) { 313 canEnter = ci.isMethodCondExecutable(ti, this); 314 } else { 315 canEnter = canEnter(ti); 316 } 317 318 return canEnter; 319 } 320 321 325 public boolean isBodySchedulingRelevant (ThreadInfo ti, ElementInfo ei) { 326 return (schedulingRelevance != SR_NEVERBODY); 327 } 328 329 332 public boolean isSchedulingRelevant (ThreadInfo ti, ElementInfo ei) { 333 switch (schedulingRelevance) { 334 case SR_ALWAYS: return true; 335 case SR_RUNNABLES: return ti.hasOtherRunnables(); 336 case SR_SYNC: 337 if (ei.getLockCount() == 0) { 338 return ti.hasOtherRunnables(); 339 } 340 } 341 342 return false; 343 } 344 345 public boolean isCtor () { 346 return (name.equals("<init>")); 347 } 348 349 public boolean isInternalMethod () { 350 return (name.equals("<clinit>") || uniqueName.equals("finalize()")); 352 } 353 354 public boolean isThreadEntry (ThreadInfo ti) { 355 return (uniqueName.equals("run()") && (ti.countStackFrames() == 1)); 356 } 357 358 361 public String getFullName () { 362 return name + signature; 363 } 364 365 368 public Instruction getInstruction (int i) { 369 if (code == null) { 370 return null; 371 } 372 373 if ((i < 0) || (i >= code.length)) { 374 return null; 375 } 376 377 return code[i]; 378 } 379 380 383 public Instruction getInstructionAt (int position) { 384 if (code == null) { 385 return null; 386 } 387 388 for (int i = 0, l = code.length; i < l; i++) { 389 if ((code[i] != null) && (code[i].getPosition() == position)) { 390 return code[i]; 391 } 392 } 393 394 throw new JPFException("instruction not found"); 395 } 396 397 400 public Instruction[] getInstructions () { 401 return code; 402 } 403 404 407 public int getLineNumber (Instruction pc) { 408 if (lineNumbers == null) { 409 return pc.getPosition(); 410 } 411 412 return lineNumbers[pc.getOffset()]; 413 } 414 415 418 public int[] getLineNumbers () { 419 return lineNumbers; 420 } 421 422 public boolean isMJI () { 423 return ((mjiAttrs & MJI_NATIVE) != 0); 424 } 425 426 public int getMaxLocals () { 427 return maxLocals; 428 } 429 430 public static int getMaxLocals (Method m) { 431 Code c = m.getCode(); 432 433 if (c == null) { 434 return 0; 435 } 436 437 return c.getMaxLocals(); 438 } 439 440 public int getMaxStack () { 441 return maxStack; 442 } 443 444 public static int getMaxStack (Method m) { 445 Code c = m.getCode(); 446 447 if (c == null) { 448 return 0; 449 } 450 451 return c.getMaxStack(); 452 } 453 454 public ExceptionHandler[] getExceptions () { 455 return exceptions; 456 } 457 458 public String [] getLocalVariableNames () { 459 return localVariableNames; 460 } 461 462 public String [] getLocalVariableTypes () { 463 return localVariableTypes; 464 } 465 466 469 public String getName () { 470 return name; 471 } 472 473 476 public boolean isNative () { 477 return isNative; 478 } 479 480 public int getNumberOfArguments () { 481 if (nArgs < 0) { 482 nArgs = Types.getNumberOfArguments(signature); 483 } 484 485 return nArgs; 486 } 487 488 492 public int getNumberOfStackArguments () { 493 int n = getNumberOfArguments(); 494 495 return isStatic ? n : n + 1; 496 } 497 498 501 public boolean isReferenceReturnType () { 502 int r = getReturnType(); 503 504 return ((r == Types.T_REFERENCE) || (r == Types.T_ARRAY)); 505 } 506 507 public byte getReturnType () { 508 if (returnType < 0) { 509 returnType = Types.getReturnType(signature); 510 } 511 512 return returnType; 513 } 514 515 518 public String getSignature () { 519 return signature; 520 } 521 522 525 public boolean isStatic () { 526 return isStatic; 527 } 528 529 532 public boolean isSynchronized () { 533 return isSynchronized; 534 } 535 536 public String getUniqueName () { 537 return uniqueName; 538 } 539 540 public boolean canEnter (ThreadInfo th) { 541 if (isSynchronized) { 542 ElementInfo ei = getBlockedObject(th, true); 543 544 return ei.canLock(th); 546 } 547 548 return true; 549 } 550 551 public ElementInfo getBlockedObject (ThreadInfo th, boolean isBeforeCall) { 552 int objref; 553 ElementInfo ei = null; 554 555 if (isSynchronized) { 556 if (isStatic) { 557 objref = ci.getClassObjectRef(); 558 } else { 559 objref = isBeforeCall ? th.getCalleeThis(this) : th.getThis(); 563 } 564 565 DynamicArea da = JVM.getVM().getDynamicArea(); 566 ei = da.get(objref); 567 568 if (ei == null) { 569 throw new JPFException("inconsistent stack, no object or class ref: " + 571 getCompleteName() + " (" + objref +")"); 572 } 573 } 574 575 return ei; 576 } 577 578 public void enter (ThreadInfo th) { 579 if (isSynchronized) { 580 ElementInfo ei = getBlockedObject(th, false); 581 ei.lock(th); 582 } 583 } 584 585 public void leave (ThreadInfo th) { 586 if (isSynchronized) { 587 ElementInfo ei = getBlockedObject(th, false); 588 ei.unlock(th); 589 } 590 } 591 592 595 public Instruction execute (ThreadInfo ti, boolean isDirectCall) { 596 if (((mjiAttrs & MJI_NATIVE) != 0) || isNative) { 597 return ci.executeNativeMethod(ti, this); 602 } else { 603 ti.pushFrame( new StackFrame(this, isDirectCall, ti.top())); 604 enter(ti); 605 606 return ti.getPC(); 607 } 608 } 609 610 613 protected Instruction[] loadCode (Method m) { 614 Code c = m.getCode(); 615 616 if (c == null) { 617 return null; 618 } 619 620 InstructionList il = new InstructionList(c.getCode()); 621 622 InstructionHandle[] hs = il.getInstructionHandles(); 623 int length = hs.length; 624 625 Instruction[] is = new Instruction[length]; 626 627 for (int i = 0; i < length; i++) { 628 is[i] = Instruction.create(hs[i], i, this, m.getConstantPool()); 629 630 if (c.getLineNumberTable() != null) { 631 is[i].setContext(ci.getName(), name, 634 c.getLineNumberTable() 635 .getSourceLine(is[i].getPosition()), 636 is[i].getPosition()); 637 } 638 } 639 640 return is; 641 } 642 643 646 protected ExceptionHandler[] loadExceptions (Method m) { 647 Code c = m.getCode(); 648 649 if (c == null) { 650 return null; 651 } 652 653 CodeException[] ce = c.getExceptionTable(); 654 655 if (ce.length == 0) { 656 return null; 657 } 658 659 int length = ce.length; 660 ExceptionHandler[] eh = new ExceptionHandler[length]; 661 662 ConstantPool cp = m.getConstantPool(); 663 664 for (int i = 0; i < length; i++) { 665 int ct = ce[i].getCatchType(); 666 eh[i] = new ExceptionHandler(((ct == 0) 667 ? null 668 : cp.getConstantString(ct, 669 Constants.CONSTANT_Class) 670 .replace('/', '.')), ce[i].getStartPC(), 671 ce[i].getEndPC(), ce[i].getHandlerPC()); 672 } 673 674 return eh; 675 } 676 677 680 protected int[] loadLineNumbers (Method m) { 681 Code c = m.getCode(); 682 683 if (c == null) { 684 return null; 685 } 686 687 LineNumberTable lnt = c.getLineNumberTable(); 688 689 int length = code.length; 690 int[] ln = new int[length]; 691 692 if (lnt == null) { 693 return null; 695 } else { 696 for (int i = 0; i < length; i++) { 697 try { ln[i] = lnt.getSourceLine(code[i].getPosition()); 699 } catch (RuntimeException e) { 700 System.out.print("^"); 701 } 702 } 703 } 704 705 return ln; 706 } 707 708 716 protected String [] loadLocalVariableNames (Method m) { 717 Code c = m.getCode(); 718 719 if (c == null) { 720 return null; 721 } 722 723 LocalVariableTable lvt = c.getLocalVariableTable(); 724 725 if (lvt == null) { 726 if (!warnedLocalInfo && !ci.isSystemClass()) { 727 Debug.println(Debug.WARNING); 728 Debug.println(Debug.WARNING, "No local variable information available"); 729 Debug.println(Debug.WARNING, "for " + getCompleteName()); 730 Debug.println(Debug.WARNING, 731 "Recompile with -g to include this information"); 732 Debug.println(Debug.WARNING); 733 warnedLocalInfo = true; 734 } 735 736 return null; 737 } 738 739 LocalVariable[] lv = lvt.getLocalVariableTable(); 740 int length = lv.length; 741 String [] v = new String [c.getMaxLocals()]; 742 743 for (int i = 0; i < length; i++) { 744 v[lv[i].getIndex()] = lv[i].getName(); 745 } 746 747 for (int i=0; i<v.length; i++) { 748 if (v[i] == null) { 749 v[i] = "?"; 750 } 751 } 752 753 return v; 754 } 755 756 761 protected String [] loadLocalVariableTypes (Method m) { 762 Code c = m.getCode(); 763 764 if (c == null) { 765 return null; 766 } 767 768 LocalVariableTable lvt = c.getLocalVariableTable(); 769 770 if (lvt == null) { 771 if (!warnedLocalInfo && !ci.isSystemClass()) { 772 Debug.println(Debug.WARNING, "No local variable information available"); 773 Debug.println(Debug.WARNING, "for " + getCompleteName()); 774 Debug.println(Debug.WARNING, 775 "Recompile with -g to include this information"); 776 Debug.println(Debug.WARNING); 777 warnedLocalInfo = true; 778 } 779 780 return null; 781 } 782 783 LocalVariable[] lv = lvt.getLocalVariableTable(); 784 int length = lv.length; 785 String [] v = new String [c.getMaxLocals()]; 786 787 for (int i = 0; i < length; i++) { 788 v[lv[i].getIndex()] = lv[i].getSignature(); 789 } 790 791 for (int i=0; i<v.length; i++) { 792 if (v[i] == null) { 793 v[i] = "?"; 794 } 795 } 796 797 return v; 798 } 799 800 void setCondDeterministic (boolean isCondDeterministic) { 801 if (isCondDeterministic) { 802 mjiAttrs |= MJI_COND_DETERMINISTIC; 803 } else { 804 mjiAttrs &= ~MJI_COND_DETERMINISTIC; 805 } 806 } 807 808 void setCondExecutable (boolean isCondExecutable) { 809 if (isCondExecutable) { 810 mjiAttrs |= MJI_COND_EXECUTABLE; 811 } else { 812 mjiAttrs &= ~MJI_COND_EXECUTABLE; 813 } 814 } 815 816 void setDeterministic (boolean isDeterministic) { 817 if (isDeterministic) { 818 mjiAttrs &= ~MJI_NONDETERMINISTIC; 819 } else { 820 mjiAttrs |= MJI_NONDETERMINISTIC; 821 } 822 } 823 824 void setMJI (boolean isMJI) { 825 if (isMJI) { 826 mjiAttrs |= MJI_NATIVE; 827 } else { 828 mjiAttrs &= ~MJI_NATIVE; 829 } 830 } 831 } 832 | Popular Tags |