KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gov > nasa > jpf > jvm > MethodInfo


1 //
2
// Copyright (C) 2005 United States Government as represented by the
3
// Administrator of the National Aeronautics and Space Administration
4
// (NASA). All Rights Reserved.
5
//
6
// This software is distributed under the NASA Open Source Agreement
7
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
8
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
9
// directory tree for the complete NOSA document.
10
//
11
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
12
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
13
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
14
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
15
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
16
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
17
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
18
//
19
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 /**
43  * information associated with a method. Each method in JPF
44  * is represented by a MethodInfo object
45  */

46 public class MethodInfo implements Cloneable JavaDoc {
47   /**
48    * Used to warn about local variable information.
49    */

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   /**
58    * scheduling relevance (used for on-the-fly POR)
59    */

60   public static final int SR_NEVER = 0; // never relevant, excl. sync blocks in body
61
public static final int SR_ALWAYS = 0x1; // always relevant
62
public static final int SR_RUNNABLES = 0x2; // only relevant if there are other runnables
63
public static final int SR_SYNC = 0x4; // only relevant if top lock level
64

65   public static final int SR_NEVERBODY = 0x8; // never relevant, incl. sync blocks in body
66

67   /**
68    * Name of the method.
69    */

70   protected String JavaDoc name;
71
72   /**
73    * Signature of the method.
74    */

75   protected String JavaDoc signature;
76
77   /**
78    * Class the method belongs to.
79    */

80   protected ClassInfo ci;
81
82   /**
83    * Instructions associated with the method.
84    */

85   protected Instruction[] code;
86
87   /**
88    * Exception handlers.
89    */

90   protected ExceptionHandler[] exceptions;
91
92   /**
93    * Table used for line numbers.
94    */

95   protected int[] lineNumbers;
96
97   /**
98    * Local variables names.
99    */

100   protected String JavaDoc[] localVariableNames;
101
102   /**
103    * Local variables types.
104    */

105   protected String JavaDoc[] localVariableTypes;
106
107   /**
108    * Static method.
109    */

110   protected boolean isStatic;
111
112   /**
113    * Synchronized method.
114    */

115   protected boolean isSynchronized;
116
117   /**
118    * that's our own attribute - execute this method atomically
119    */

120   protected boolean isAtomic;
121   
122   /**
123    * Native method.
124    */

125   protected boolean isNative;
126
127   /**
128    * is this a scheduling relevant method (step boundary)
129    */

130   protected int schedulingRelevance;
131   
132   /**
133    * Maximum number of local variables.
134    */

135   protected int maxLocals;
136
137   /**
138    * Maximum number of elements on the stack.
139    */

140   protected int maxStack;
141
142   // <2do> pcm - turn this into a derived class, it's only required for MJI methods
143

144   /**
145    * the number of stack slots for the arguments (incl. 'this'), lazy eval
146    */

147   private int argSize = -1;
148
149   /**
150    * number of arguments (excl. 'this'), lazy eval
151    */

152   private int nArgs = -1;
153
154   /**
155    * what return type do we have (again, lazy evaluated)
156    */

157   private byte returnType = -1;
158
159   /**
160    * used for native method parameter conversion (lazy evaluated)
161    */

162   private byte[] argTypes = null;
163
164   /**
165    * the various MJI method attrs (we don't want to burn 12 bytes for them
166    */

167   int mjiAttrs = MJI_NONE;
168
169   /**
170    * this is a lazy evaluated mangled name consisting of the name and
171    * arg type signature
172    */

173   private String JavaDoc uniqueName;
174   
175   /**
176    * Creates a new method info.
177    */

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     // since that's used to store the method in the ClassInfo, and to
195
// identify it in tne InvokeInstruction, we can set it here
196
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 JavaDoc clone() {
212     try {
213       return super.clone();
214     } catch (CloneNotSupportedException JavaDoc cnx) {
215       return null;
216     }
217   }
218   
219   /**
220    * NOTE - this only works in conjunction with a special StackFrame
221    */

222   MethodInfo createNativeCallStub () {
223     MethodInfo mi = (MethodInfo) clone();
224     String JavaDoc 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     // otherwise ThreadInfo.executeAtomicLinesStep chokes up
240
mi.lineNumbers = null;
241     mi.exceptions = null;
242     
243     return mi;
244   }
245
246   
247   /**
248    * return the minimal name that has to be unique for overloading
249    * (name + argument part of signature)
250    * used as a lookup key
251    */

252   public static String JavaDoc getUniqueName (String JavaDoc mname, String JavaDoc 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   /**
286    * Returns the class the method belongs to.
287    */

288   public ClassInfo getClassInfo () {
289     return ci;
290   }
291
292   /**
293    * Return the complete name of the method, including the class name.
294    */

295   public String JavaDoc 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       // really just makes sense if this is a MJI method
304
// but we will factor this into a subclass later-on anyway
305
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   /**
322    * do we honor scheduling relevant insns in our body, or do we
323    * (hopefully deliberately) ignore them
324    */

325   public boolean isBodySchedulingRelevant (ThreadInfo ti, ElementInfo ei) {
326     return (schedulingRelevance != SR_NEVERBODY);
327   }
328   
329   /**
330    * is invocation of this method scheduling relevant
331    */

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     // <2do> pcm - should turn this into an attribute for efficiency reasons
351
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   /**
359    * Returns the full name of the method, name and signature.
360    */

361   public String JavaDoc getFullName () {
362     return name + signature;
363   }
364
365   /**
366    * Returns a specific instruction.
367    */

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   /**
381    * Returns the instruction at a certain position.
382    */

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   /**
398    * Returns the instructions of the method.
399    */

400   public Instruction[] getInstructions () {
401     return code;
402   }
403
404   /**
405    * Returns the line number for a given position.
406    */

407   public int getLineNumber (Instruction pc) {
408     if (lineNumbers == null) {
409       return pc.getPosition();
410     }
411
412     return lineNumbers[pc.getOffset()];
413   }
414
415   /**
416    * Returns a table to translate positions into line numbers.
417    */

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 JavaDoc[] getLocalVariableNames () {
459     return localVariableNames;
460   }
461
462   public String JavaDoc[] getLocalVariableTypes () {
463     return localVariableTypes;
464   }
465
466   /**
467    * Returns the name of the method.
468    */

469   public String JavaDoc getName () {
470     return name;
471   }
472
473   /**
474    * Returns true if the method is native
475    */

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   /**
489    * Returns the size of the arguments.
490    * This returns the number of parameters passed on the stack, incl. 'this'
491    */

492   public int getNumberOfStackArguments () {
493     int n = getNumberOfArguments();
494
495     return isStatic ? n : n + 1;
496   }
497
498   /**
499    * do we return Object references?
500    */

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   /**
516    * Returns the signature of the method.
517    */

518   public String JavaDoc getSignature () {
519     return signature;
520   }
521
522   /**
523    * Returns true if the field is static.
524    */

525   public boolean isStatic () {
526     return isStatic;
527   }
528
529   /**
530    * Returns true if the field is synchronized.
531    */

532   public boolean isSynchronized () {
533     return isSynchronized;
534   }
535   
536   public String JavaDoc getUniqueName () {
537     return uniqueName;
538   }
539
540   public boolean canEnter (ThreadInfo th) {
541     if (isSynchronized) {
542       ElementInfo ei = getBlockedObject(th, true);
543
544       // <?> pcm - the other way round would be intuitive
545
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         // NOTE 'inMethod' doesn't work for natives, because th.getThis()
560
// pulls 'this' from the stack frame, which we don't have (and don't need)
561
// for natives
562
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         // ARGHH, broken this or class
570
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   /**
593    * execute this method, which might be either bytecode or native.
594    */

595   public Instruction execute (ThreadInfo ti, boolean isDirectCall) {
596     if (((mjiAttrs & MJI_NATIVE) != 0) || isNative) {
597       // if we have a native method which is not MJI_NATIVE, we are in
598
// trouble (ends up in UnsatisfiedLinkErrors)
599
// the opposite (MJI_NATIVE but not native) is questionable, but legal
600
// (you better know what code you cut off)
601
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   /**
611    * Loads the code of the method.
612    */

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         // annoying bug when BCEL don't seem to find linenumber - pos match
632
// also sometimes linenumber tables are not available
633
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   /**
644    * Returns the exceptions of the method.
645    */

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   /**
678    * Loads the line numbers for the method.
679    */

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       // no line information
694
return null;
695     } else {
696       for (int i = 0; i < length; i++) {
697         try { //annoying bug when BCEL don't seem to find linenumber - pos match
698
ln[i] = lnt.getSourceLine(code[i].getPosition());
699         } catch (RuntimeException JavaDoc e) {
700           System.out.print("^");
701         }
702       }
703     }
704
705     return ln;
706   }
707
708   /**
709    * Loads the names of the local variables.
710    *
711    * NOTE: BCEL only gives us a list of all *named* locals, which might not
712    * include all local vars (temporaries, like StringBuffer). Note that we have
713    * to fill this with "?" inorder to make the returned array correspond with
714    * slot numbers
715    */

716   protected String JavaDoc[] 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 JavaDoc[] v = new String JavaDoc[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   /**
757    * Loads the types of the local variables.
758    * see loadLocalVariableNames for the problem with temporaries and
759    * why we can't copy the types 1:1
760    */

761   protected String JavaDoc[] 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 JavaDoc[] v = new String JavaDoc[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