Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

ThreadInfo.java

00001 package gov.nasa.arc.ase.jpf.jvm;
00002 
00003 import gov.nasa.arc.ase.jpf.Engine;
00004 import gov.nasa.arc.ase.jpf.InternalErrorException;
00005 import gov.nasa.arc.ase.jpf.iThreadInfo;
00006 import gov.nasa.arc.ase.jpf.JPFErrorException;
00007 import gov.nasa.arc.ase.jpf.jvm.bytecode.Instruction;
00008 import gov.nasa.arc.ase.jpf.jvm.bytecode.ReturnInstruction;
00009 import gov.nasa.arc.ase.jpf.jvm.bytecode.InvokeInstruction;
00010 import gov.nasa.arc.ase.jpf.jvm.bytecode.INVOKESTATIC;
00011 import gov.nasa.arc.ase.util.Debug;
00012 import gov.nasa.arc.ase.util.HashData;
00013 import gov.nasa.arc.ase.util.HashPool;
00014 import gov.nasa.arc.ase.util.Right;
00015 import java.util.BitSet;
00016 import java.util.Set;
00017 import java.util.HashSet;
00018 //#ifdef JDK11
00019 
00020 //#else JDK11
00021 import java.util.LinkedList;
00022 //#endif JDK11
00023 //#ifdef REACHABILITY
00024 
00025 
00026 //#endif REACHABILITY
00027 //#ifdef RACE
00028 
00029 
00030 //#endif RACE
00031 //#ifdef LOCK_ORDER
00032 
00033 
00034 
00035 
00036 //#endif LOCK_ORDER
00037 //#ifdef COVERAGE
00038 
00039 //#endif COVERAGE
00040 
00041 /**
00042  * Represents a thread. It contains the state of the thread, static
00043  * information about the thread, and the stack frames.
00044  * Race detection and lock order also store some information
00045  * in this data structure.
00046  */
00047 public class ThreadInfo implements iThreadInfo, Storable, Thread {
00048   /**
00049    * Pool used to store the thread data.
00050    */
00051   private static HashPool threadDataPool = new HashPool();
00052 
00053   /**
00054    * Pool used to store the stack frames.
00055    */
00056   private static HashPool stackFramePool = new HashPool();
00057 
00058   /**
00059    * Information about the thread.
00060    */
00061   private ThreadData threadData;
00062 
00063   /**
00064    * Some information about the thread that are used to handle
00065    * atomicity.
00066    */
00067   private AtomicData atomicData;
00068 
00069   /**
00070    * The stack frames of the JVM. 
00071    */
00072   private StackFrame[] stack;
00073 
00074   /**
00075    * Reference of the thread list it is in.
00076    */
00077   public ThreadList list;
00078 
00079   /**
00080    * Position in the thread list.
00081    */
00082   public int index;
00083 
00084   /**
00085    * Contains the index of the thread data last used.
00086    */
00087   public int tdIndex = -1;
00088 
00089   /**
00090    * Identifies which thread has changed.
00091    */
00092   public BitSet hasChanged;
00093 
00094   /**
00095    * Set if any stack frame changed.
00096    */
00097   public boolean anyChanged;
00098 
00099   /**
00100    * Keeps the information from the last storing.
00101    */
00102   private int[] data;
00103 
00104   /**
00105    * Remembers which is the lowest changed stack frame.
00106    */
00107   private int lowestChanged;
00108   
00109   /**
00110    * Creates a new empty thread info. Used to backtrack.
00111    */
00112   ThreadInfo() {
00113     stack = new StackFrame[0];
00114     tdIndex = -1;
00115     data = new int[0];
00116     hasChanged = new BitSet();
00117   }  
00118   /**
00119    * Creates a new thread info. It is associated with the object
00120    * passed and sets the target object as well.
00121    */
00122   public ThreadInfo(int o) {
00123     threadData = new ThreadData();
00124     threadData.status = NEW;
00125     if(o != -1)
00126       threadData.ci = VirtualMachine.getSS().ks.da.get(o).getClassInfo();
00127     threadData.objref = o;
00128     threadData.target = -1;
00129     threadData.lockCount = 0;
00130 //#ifdef RACE
00131 
00132 
00133 
00134 
00135 //#endif RACE
00136 //#ifdef LOCK_ORDER
00137 
00138 
00139 
00140 
00141 
00142 
00143 
00144 //#endif LOCK_ORDER
00145 
00146     atomicData = new AtomicData();
00147     atomicData.currentMethod = null;
00148     atomicData.line = -1;
00149     atomicData.inSameMethod = false;
00150     atomicData.softAtomicLevel = 0;
00151 
00152     stack = new StackFrame[0];
00153 
00154     hasChanged = new BitSet();
00155     anyChanged = false;
00156     data = new int[0];
00157     lowestChanged = -1;
00158   }  
00159   public ThreadInfo(ThreadInfo ti) {
00160     if(ti.tdIndex == -1)
00161       threadData = (ThreadData)ti.threadData.clone();
00162     else
00163       threadData = ti.threadData;
00164 
00165     atomicData = (AtomicData)ti.atomicData.clone();
00166 
00167     if(ti.stack != null) {
00168       int l = ti.stack.length;
00169       stack = new StackFrame[l];
00170       if(ti.anyChanged)
00171     for(int i = 0; i < l; i++)
00172       if(ti.hasChanged.get(i))
00173         stack[i] = (StackFrame)ti.stack[i].clone();
00174       else
00175         stack[i] = ti.stack[i];
00176       else
00177     System.arraycopy(ti.stack, 0, stack, 0, l);
00178     } else
00179       stack = null;
00180 
00181     list = null;
00182 
00183     index = -1;
00184 
00185     tdIndex = ti.tdIndex;
00186 
00187     hasChanged = (BitSet)ti.hasChanged.clone();
00188 
00189     anyChanged = ti.anyChanged;
00190 
00191     data = ti.data;
00192 
00193     lowestChanged = ti.lowestChanged;
00194   }  
00195   public boolean atInvoke(String mname) {
00196     if(stack.length == 0) return false;
00197 
00198     Instruction pc = getPC();
00199 
00200     if(!(pc instanceof InvokeInstruction)) return false;
00201     
00202     InvokeInstruction i = (InvokeInstruction)pc;
00203     
00204     return mname.equals(i.cname + "." + i.mname);
00205   }  
00206   public boolean atLabel(String label) {
00207 //#ifdef BUCHI
00208     return Labels.isAt(label, this);
00209 //#else BUCHI
00210 
00211 //#endif BUCHI
00212   }  
00213   public boolean atMethod(String mname) {
00214     if(stack.length == 0) return false;
00215 
00216     return getMethod().getCompleteName().equals(mname);
00217   }  
00218   public boolean atPosition(int position) {
00219     if(stack.length == 0) return false;
00220 
00221     Instruction pc = getPC();
00222 
00223     if(pc == null) return false;
00224 
00225     return pc.getPosition() == position;
00226   }  
00227   public boolean atReturn() {
00228     if(stack.length == 0) return false;
00229 
00230     Instruction pc = getPC();
00231 
00232     if(pc == null) return false;
00233 
00234     return pc instanceof ReturnInstruction;
00235   }  
00236   /**
00237    * Restores the state of the system.
00238    */
00239   public void backtrackTo(ArrayOffset storing, Object backtrack) {
00240     setThreadDataIndex(storing.get());
00241     
00242     int length = storing.get();
00243     int l = stack.length;
00244 
00245     int[] data = new int[length+2];
00246     data[0] = tdIndex;
00247     data[1] = length;
00248     System.arraycopy(storing.data, storing.offset, data, 2, length);
00249 
00250     if(length != l) {
00251       if(l > length) l = length;
00252       StackFrame[] n = new StackFrame[length];
00253       if(l > 0)
00254     System.arraycopy(stack, 0, n, 0, l);
00255       stack = n;
00256     }
00257     
00258     for(int i = 0; i < length; i++)
00259       setStackFrameIndex(i, storing.get());
00260 
00261     atomicData = (AtomicData)backtrack;
00262 
00263     anyChanged = false;
00264     hasChanged = new BitSet();
00265     lowestChanged = -1;
00266 
00267     this.data = data;
00268   }  
00269   /**
00270    * Pops a set of values from the caller stack frame.
00271    */
00272   public void callerPop(int n) {
00273     frameClone(-1).pop(n);
00274   }  
00275   /**
00276    * Clears the operand stack of all value.
00277    */
00278   public void clearOperandStack() {
00279     topClone().clearOperandStack();
00280   }  
00281 //#ifdef DISTRIBUTED || PARALLEL
00282 
00283 
00284 
00285 
00286 
00287 
00288 
00289 
00290 //#endif DISTRIBUTED || PARALLEL
00291 
00292   public Object clone() {
00293     return new ThreadInfo(this);
00294   }  
00295   /**
00296    * Returns the number of stack frames.
00297    */
00298   public int countStackFrames() {
00299     return stack.length;
00300   }  
00301   /**
00302    * Creates an exception and throws it.
00303    */
00304   public Instruction createAndThrowException(ClassInfo ci) {
00305     int objref = list.ks.da.newObject(ci, this);
00306 
00307     return throwException(objref);
00308   }  
00309   /**
00310    * Creates an exception and throws it.
00311    */
00312   public Instruction createAndThrowException(String cname) {
00313     return createAndThrowException(ClassInfo.getClassInfo(cname));
00314   }  
00315   /**
00316    * Creates a stack frame for a newly called method.
00317    */
00318   public void createMethodStackFrame(MethodInfo mi) {
00319     int nargs = mi.getArgumentsSize();
00320     int[] args = new int[nargs];
00321     boolean[] refs = new boolean[nargs];
00322     if(nargs > 0) {
00323       StackFrame sf = top();
00324 
00325       for(int i = 0, cnt = nargs-1; i < nargs; i++, cnt--) {
00326     args[cnt] = sf.peek(i);
00327     refs[cnt] = sf.isOperandRef(i);
00328       }
00329     }
00330 
00331     newFrame(mi);
00332 
00333     if(nargs > 0) {
00334       StackFrame sf = top();
00335 
00336       for(int i = 0; i < nargs; i++)
00337     setLocalVariable(i, args[i], refs[i]);
00338     }
00339   }  
00340   /**
00341    * Duplicates a value on the top stack frame.
00342    */
00343   public void dup() {
00344     topClone().dup();
00345   }  
00346   /**
00347    * Duplicates a value on the top stack frame.
00348    */
00349   public void dup_x1() {
00350     topClone().dup_x1();
00351   }  
00352   /**
00353    * Duplicates a value on the top stack frame.
00354    */
00355   public void dup_x2() {
00356     topClone().dup_x2();
00357   }  
00358   /**
00359    * Duplicates a long value on the top stack frame.
00360    */
00361   public void dup2() {
00362     topClone().dup2();
00363   }  
00364   /**
00365    * Duplicates a long value on the top stack frame.
00366    */
00367   public void dup2_x1() {
00368     topClone().dup2_x1();
00369   }  
00370   /**
00371    * Duplicates a long value on the top stack frame.
00372    */
00373   public void dup2_x2() {
00374     topClone().dup2_x2();
00375   }  
00376   /**
00377    * Starts a soft atomic block.
00378    */
00379   public void enterSoftAtomic() {
00380     atomicData.softAtomicLevel++;
00381   }  
00382   /**
00383    * Executes a step where lines are atomic.
00384    * @return false if intermediate step (due to Nondeterminism or Buchi observable)
00385    */
00386   private boolean executeAtomicLinesStep() {
00387     atomicData.line = getLine();
00388     atomicData.currentMethod = getMethod();
00389     atomicData.inSameMethod = true;
00390 
00391     int[] lines = atomicData.currentMethod.getLineNumbers();
00392 
00393     if(list.ks.ss.ti == null)
00394       list.ks.ss.ti = new TrailInfo(index, list.ks.ss.sch.getRandom());
00395 
00396 //#ifdef LIVELOCK_IN_ATOMIC
00397 
00398 
00399 //#endif LIVELOCK_IN_ATOMIC
00400 
00401     while(true) {
00402       Instruction pc = executeInstruction();
00403     
00404       if(list.ks.ss.violatedAssertion) break;
00405     
00406 //#ifdef LIVELOCK_IN_ATOMIC
00407 
00408 
00409 
00410 
00411 
00412 
00413 
00414 
00415 
00416 //#endif LIVELOCK_IN_ATOMIC
00417 
00418       Engine.getJPF().status.instructions++;
00419 
00420       if(pc == null) break;
00421 
00422 //#ifdef BUCHI
00423       if(pc.isObservable()) {
00424     list.ks.ss.ti.addComment("observable instruction");
00425     return false;
00426       }
00427 //#endif BUCHI
00428 
00429       if(pc.examine(list.ks.ss, list.ks, this)) {
00430     return false;
00431       }
00432 
00433       if(list.ks.atomicLevel != 0) {
00434     if(!isRunnable()) {
00435       printStackTrace();
00436       throw new JPFErrorException("Non-executable statement in atomic block");
00437     }
00438     continue;
00439       }
00440 
00441       if(!isRunnable()) break;
00442 
00443       if(atomicData.softAtomicLevel != 0) {
00444     continue;
00445       }
00446 
00447       if(!atomicData.inSameMethod || (
00448         atomicData.line != lines[pc.getOffset()] && 
00449         !(pc instanceof ReturnInstruction))) {
00450     atomicData.currentMethod = null;
00451     atomicData.line = -1;
00452     break;
00453       }
00454     }
00455 
00456 //#ifdef REACHABILITY
00457 
00458 
00459 
00460 
00461 
00462 
00463 
00464 
00465 
00466 
00467 //#endif REACHABILITY
00468 
00469     return true;
00470   }  
00471   /**
00472    * Execute next instruction.
00473    */
00474   public Instruction executeInstruction() {
00475     Instruction pc = getPC();
00476 //#ifdef COVERAGE
00477 //#ifdef HEURISTIC
00478 
00479 
00480 //#endif HEURISTIC
00481 //#endif COVERAGE
00482 //#ifdef DEBUG
00483 
00484 //#endif DEBUG
00485 
00486     list.ks.ss.ti.addStep(getMethod().getClassInfo().getName(), getLine());
00487     list.ks.ss.ti.addBytecode(pc);
00488 
00489     // execute the next bytecode
00490     pc = pc.execute(list.ks.ss, list.ks, this);
00491 
00492     // we did not return from the last frame stack
00493     if(stack.length != 0) setPC(pc);
00494 
00495     return pc;
00496   }  
00497   /**
00498    * Executes a method call. It executes the whole method as one * atomic step and returns when the call is over. It also allows
00499    * for methods to be reflected. The arguments to the method
00500    * must already be onto the stack.
00501    */
00502   public void executeMethod(MethodInfo mi) {
00503     int depth = countStackFrames();
00504 
00505     // first sets the trail information so that we can reconstruct the trail
00506     if(list.ks.ss.ti == null)
00507       list.ks.ss.ti = new TrailInfo(index, list.ks.ss.sch.getRandom());
00508 
00509 //#ifdef LIVELOCK_IN_ATOMIC
00510 
00511 
00512 //#endif LIVELOCK_IN_ATOMIC
00513 
00514     mi.getClassInfo().executeMethod(this, mi.getFullName());
00515     while(depth < countStackFrames()) {
00516       Instruction pc = executeInstruction();
00517     
00518       if(list.ks.ss.violatedAssertion) break;
00519     
00520 //#ifdef LIVELOCK_IN_ATOMIC
00521 
00522 
00523 
00524 
00525 
00526 
00527 
00528 
00529 
00530 //#endif LIVELOCK_IN_ATOMIC
00531 
00532       Engine.getJPF().status.instructions++;
00533 
00534       if(pc == null)
00535     throw new InternalErrorException("pc == null in executeMethod");
00536 
00537       if(!isRunnable())
00538     throw new InternalErrorException("blocked in executeMethod");
00539     }
00540   }  
00541   /**
00542    * execute a step without considering lines to be atomic.
00543    */
00544   private boolean executeNoAtomicLinesStep() {
00545     // first sets the trail information so that we can reconstruct the trail
00546     if(list.ks.ss.ti == null)
00547       list.ks.ss.ti = new TrailInfo(index, list.ks.ss.sch.getRandom());
00548 
00549 //#ifdef LIVELOCK_IN_ATOMIC
00550 
00551 
00552 //#endif LIVELOCK_IN_ATOMIC
00553 
00554     while(true) {
00555       Instruction pc = executeInstruction();
00556 
00557       if(list.ks.ss.violatedAssertion) break;
00558     
00559 //#ifdef LIVELOCK_IN_ATOMIC
00560 
00561 
00562 
00563 
00564 
00565 
00566 
00567 
00568 //#endif LIVELOCK_IN_ATOMIC
00569 
00570       Engine.getJPF().status.instructions++;
00571 
00572       if(pc == null) break;
00573       
00574 //#ifdef BUCHI
00575       if(pc.isObservable()) {
00576     list.ks.ss.ti.addComment("observable instruction");
00577     return false;
00578       }
00579 //#endif BUCHI
00580 
00581       if(pc.examine(list.ks.ss, list.ks, this))
00582     return false;
00583 
00584       if(list.ks.atomicLevel != 0) {
00585     if(!isRunnable()) {
00586       printStackTrace();
00587       throw new JPFErrorException("Non-executable statement in atomic block");
00588     }
00589     continue;
00590       }
00591       if(!isRunnable()) break;
00592       if(atomicData.softAtomicLevel != 0) {
00593     continue;
00594       }
00595 
00596       break;
00597     }
00598 
00599 //#ifdef REACHABILITY
00600 
00601 
00602 
00603 
00604 
00605 
00606 
00607 
00608 
00609 
00610 //#endif REACHABILITY
00611 
00612     return true;
00613   }  
00614   /**
00615    * Executes a static method call. It executes the whole method as one
00616    * atomic step and returns when the call is over. It also allows
00617    * for methods to be reflected. The arguments to the method
00618    * must already be onto the stack.
00619    */
00620   public void executeStaticMethod(MethodInfo mi) {
00621     int depth = countStackFrames();
00622 
00623     // first sets the trail information so that we can reconstruct the trail
00624     if(list.ks.ss.ti == null)
00625       list.ks.ss.ti = new TrailInfo(index, list.ks.ss.sch.getRandom());
00626 
00627 //#ifdef LIVELOCK_IN_ATOMIC
00628 
00629 
00630 //#endif LIVELOCK_IN_ATOMIC
00631 
00632     mi.getClassInfo().executeStaticMethod(this, mi.getFullName());
00633     while(depth < countStackFrames()) {
00634       Instruction pc = executeInstruction();
00635 
00636       if(list.ks.ss.violatedAssertion) break;
00637     
00638 //#ifdef LIVELOCK_IN_ATOMIC
00639 
00640 
00641 
00642 
00643 
00644 
00645 
00646 
00647 
00648 //#endif LIVELOCK_IN_ATOMIC
00649 
00650       Engine.getJPF().status.instructions++;
00651 
00652       if(pc == null)
00653     break;
00654 
00655       if(!pc.isExecutable(list.ks.ss, list.ks, this)) {
00656     list.ks.jvmError(new InternalErrorException("blocked in executeStaticMethod"), this);
00657       }
00658     }
00659   }  
00660   /**
00661    * Executes next step.
00662    * @return false if intermediate step (due to Nondeterminism or Buchi observable)
00663    */
00664   public boolean executeStep() {
00665 //#ifdef DEBUG
00666 
00667 //#endif DEBUG
00668     if(VirtualMachine.options.atomic_lines)
00669       return executeAtomicLinesStep();
00670     else
00671       return executeNoAtomicLinesStep();
00672   }  
00673   /**
00674    * Returns a specific stack frame.
00675    */
00676   private StackFrame frame(int idx) {
00677     if(idx < 0) idx += stack.length - 1;
00678 
00679     return stack[idx];
00680   }  
00681   /**
00682    * Returns a clone of a specific stack frame.
00683    */
00684   private StackFrame frameClone(int i) {
00685     if(i < 0) i += stack.length - 1;
00686 
00687     if(hasChanged.get(i)) return stack[i];
00688 
00689     hasChanged.set(i);
00690     anyChanged = true;
00691     list.ks.data = null;
00692     if(lowestChanged == -1 || lowestChanged > i)
00693       lowestChanged = i;
00694 
00695     return stack[i] = (StackFrame)stack[i].clone();
00696   }  
00697   /**
00698    * Returns the information necessary to backtrack.
00699    */
00700   public Object getBacktrackData() {
00701     return atomicData.clone();
00702   }  
00703   public boolean getBooleanLocal(int lindex) { return Types.intToBoolean(getLocalVariable(lindex)); }  
00704   public boolean getBooleanLocal(String lname) { return Types.intToBoolean(getLocalVariable(lname)); }  
00705   public boolean getBooleanReturnValue() { return Types.intToBoolean(peek()); }  
00706   public byte getByteLocal(int lindex) { return (byte)getLocalVariable(lindex); }  
00707   public byte getByteLocal(String lname) { return (byte)getLocalVariable(lname); }  
00708   public byte getByteReturnValue() { return (byte)peek(); }  
00709   /**
00710    * Returns the this pointer of the callee from the stack.
00711    */
00712   public int getCalleeThis(int size) {
00713     return top().getCalleeThis(size);
00714   }  
00715   /**
00716    * Returns the this pointer of the callee from the stack.
00717    */
00718   public int getCalleeThis(MethodInfo mi) {
00719     return top().getCalleeThis(mi);
00720   }  
00721   public String[] getCallStack() {
00722     int size = stack.length;
00723     String[] callStack = new String[size];
00724 
00725     for(int i = 0; i < size; i++) {
00726       StackFrame sf = frame(i);
00727       
00728       callStack[i] = sf.getClassInfo().getName() + "." +
00729     sf.getMethodInfo().getName() + " line " +
00730     sf.getLine();
00731     }
00732 
00733     return callStack;
00734   }  
00735   public char getCharLocal(int lindex) { return (char)getLocalVariable(lindex); }  
00736   public char getCharLocal(String lname) { return (char)getLocalVariable(lname); }  
00737   public char getCharReturnValue() { return (char)peek(); }  
00738   /**
00739    * Returns the class information.
00740    */
00741   public ClassInfo getClassInfo() {
00742     return threadData.ci;
00743   }  
00744   public double getDoubleLocal(int lindex) { return Types.longToDouble(getLongLocalVariable(lindex)); }  
00745   public double getDoubleLocal(String lname) { return Types.longToDouble(getLongLocalVariable(lname)); }  
00746   public double getDoubleReturnValue() { return Types.longToDouble(longPeek()); }  
00747   public float getFloatLocal(int lindex) { return Types.intToFloat(getLocalVariable(lindex)); }  
00748   public float getFloatLocal(String lname) { return Types.intToFloat(getLocalVariable(lname)); }  
00749   public float getFloatReturnValue() { return Types.intToFloat(peek()); }  
00750   public int getIntLocal(int lindex) { return getLocalVariable(lindex); }  
00751   public int getIntLocal(String lname) { return getLocalVariable(lname); }  
00752   public int getIntReturnValue() { return peek(); }  
00753   /**
00754    * Returns the line number of the program counter of the top stack frame.
00755    */
00756   public int getLine() {
00757     return top().getLine();
00758   }  
00759   /**
00760    * Returns the line the thread is at.
00761    */
00762   public int getLine(int idx) {
00763     return frame(idx).getLine();
00764   }  
00765   /**
00766    * Returns the value of a local variable.
00767    */
00768   public int getLocalVariable(int idx) {
00769     return top().getLocalVariable(idx);
00770   }  
00771   /**
00772    * Gets the value of a local variable from its name.
00773    */
00774   public int getLocalVariable(String name) {
00775     return top().getLocalVariable(name);
00776   }  
00777   /**
00778    * Gets the type associated with a local variable.
00779    */
00780   public String getLocalVariableType(String name) {
00781     return top().getLocalVariableType(name);
00782   }  
00783   /**
00784    * Returns the number of locks in the last wait.
00785    */
00786   public int getLockCount(){
00787     return threadData.lockCount;
00788   }  
00789   public long getLongLocal(int lindex) { return getLongLocalVariable(lindex); }  
00790   public long getLongLocal(String lname) { return getLongLocalVariable(lname); }  
00791   /**
00792    * Returns the value of a long local variable.
00793    */
00794   public long getLongLocalVariable(int idx) {
00795     return top().getLongLocalVariable(idx);
00796   }  
00797   /**
00798    * Gets the value of a long local variable from its name.
00799    */
00800   public long getLongLocalVariable(String name) {
00801     return top().getLongLocalVariable(name);
00802   }  
00803   public long getLongReturnValue() { return longPeek(); }  
00804   /**
00805    * Returns the current method in the top stack frame.
00806    */
00807   public MethodInfo getMethod() {
00808     return top().getMethodInfo();
00809   }  
00810   /**
00811    * Returns the method info of a specific stack frame.
00812    */
00813   public MethodInfo getMethod(int idx) {
00814     return frame(idx).getMethodInfo();
00815   }  
00816   public Reference getObjectLocal(int lindex) { return list.ks.da.get(getLocalVariable(lindex)); }  
00817   public Reference getObjectLocal(String lname) { return list.ks.da.get(getLocalVariable(lname)); }  
00818 //#ifdef LOCK_ORDER
00819 
00820 
00821 
00822 
00823 
00824 
00825 
00826 //#endif LOCK_ORDER
00827 
00828 //#ifdef RACE || LOCK_ORDER
00829 
00830 
00831 
00832 
00833 
00834 //#ifdef LOCK_ORDER
00835 
00836 
00837 
00838 
00839 
00840 
00841 
00842 
00843 
00844 
00845 
00846 
00847 //#endif LOCK_ORDER
00848 //#ifdef RACE
00849 
00850 
00851 //#endif RACE
00852 
00853 
00854 
00855 
00856 
00857 
00858 
00859 //#ifdef LOCK_ORDER
00860 
00861 //#endif LOCK_ORDER
00862 //#ifdef RACE
00863 
00864 
00865 //#endif RACE
00866 
00867 //#endif RACE || LOCK_ORDER
00868 
00869   /**
00870    * Returns the object reference.
00871    */
00872   public int getObjectReference() {
00873     return threadData.objref;
00874   }  
00875   public Reference getObjectReturnValue() { return list.ks.da.get(peek()); }  
00876   /**
00877    * Returns the program counter of the top stack frame.
00878    */
00879   public Instruction getPC() {
00880     if(stack.length == 0) return null;
00881 
00882     return top().getPC();
00883   }  
00884   /**
00885    * Returns the program counter of a stack frame.
00886    */
00887   public Instruction getPC(int i) {
00888     return frame(i).getPC();
00889   }  
00890   public short getShortLocal(int lindex) { return (short)getLocalVariable(lindex); }  
00891   public short getShortLocal(String lname) { return (short)getLocalVariable(lname); }  
00892   public short getShortReturnValue() { return (short)peek(); }  
00893   private int getStackFrameIndex(int i) {
00894     if(hasChanged.get(i)) {
00895       HashPool.PoolEntry e = stackFramePool.getEntry(stack[i]);
00896 
00897       stack[i] = (StackFrame)e.getObject();
00898 
00899       return e.getIndex();
00900     } else
00901       return data[i+2];
00902   }  
00903   /**
00904    * Returns the current status of the thread.
00905    */
00906   public int getStatus() {
00907     return threadData.status;
00908   }  
00909   /**
00910    * Returns the information necessary to store.
00911    */
00912   public int[] getStoringData() {
00913     int length = stack.length;
00914 
00915     int[] data = new int[length+2];
00916     data[0] = getThreadDataIndex();
00917     data[1] = length;
00918 
00919     if(anyChanged) {
00920       if(lowestChanged > 0)
00921     System.arraycopy(this.data, 2, data, 2, lowestChanged);
00922 
00923       for(int i = lowestChanged, j = i+2; i < length; i++, j++)
00924     data[j] = getStackFrameIndex(i);
00925     } else
00926       if(length > 0)
00927     System.arraycopy(this.data, 2, data, 2, length);
00928 
00929     anyChanged = false;
00930     hasChanged = new BitSet();
00931     lowestChanged = -1;
00932 
00933     this.data = data;
00934 
00935     return data;
00936   }  
00937   public String getStringLocal(int lindex) { return list.ks.da.get(getLocalVariable(lindex)).asString(); }  
00938   public String getStringLocal(String lname) { return list.ks.da.get(getLocalVariable(lname)).asString(); }  
00939   public String getStringReturnValue() { return list.ks.da.get(peek()).asString(); }  
00940   /**
00941    * Returns the object reference of the target.
00942    */
00943   public int getTarget() {
00944     return threadData.target;
00945   }  
00946   /**
00947    * Returns the pointer to the object reference.
00948    */
00949   public int getThis() {
00950     return top().getThis();
00951   }  
00952 //#ifdef DISTRIBUTED
00953 
00954 
00955 
00956 
00957 
00958 
00959 
00960 
00961 
00962 //#endif DISTRIBUTED
00963 
00964   private int getThreadDataIndex() {
00965     if(tdIndex != -1) return tdIndex;
00966 
00967     HashPool.PoolEntry e = threadDataPool.getEntry(threadData);
00968     threadData = (ThreadData)e.getObject();
00969     
00970     return tdIndex = e.getIndex();
00971   }  
00972   public void hash(HashData hd) {
00973     threadData.hash(hd);
00974     atomicData.hash(hd);
00975 
00976     for(int i = 0, l = stack.length; i < l; i++)
00977       frame(i).hash(hd);
00978   }  
00979   public int hashCode() {
00980     HashData hd = new HashData();
00981 
00982     hash(hd);
00983 
00984     return hd.getValue();
00985   }  
00986   public void interrupt() {
00987     if(getStatus() != WAITING) return;
00988 
00989     setStatus(INTERRUPTED);
00990   }  
00991   /**
00992    * An alive thread is either running, waiting, notified, or interrupted.
00993    */
00994   public boolean isAlive(){
00995     return threadData.status == RUNNING || 
00996       threadData.status == WAITING || 
00997       threadData.status == INTERRUPTED || 
00998       threadData.status == NOTIFIED;
00999   }  
01000   public boolean isCalleeThis(Reference r) {
01001     if(stack.length == 0) return false;
01002 
01003     Instruction pc = getPC();
01004 
01005     if(pc == null) return false;
01006 
01007     if(!(pc instanceof InvokeInstruction)) return false;
01008     if(pc instanceof INVOKESTATIC) return false;
01009     
01010     InvokeInstruction i = (InvokeInstruction)pc;
01011     
01012     return getCalleeThis(Types.getArgumentsSize(i.signature)) ==
01013       ((ElementInfo)r).index;
01014   }  
01015   /**
01016    * An enabled thread is either running, notified, or interrupted.
01017    * It also checks if it belongs to the race window.
01018    */
01019   public boolean isEnabled() {
01020 //#ifdef RACE
01021 
01022 
01023 
01024 
01025 //#endif RACE
01026       return threadData.status == RUNNING || 
01027     threadData.status == INTERRUPTED || 
01028     threadData.status == NOTIFIED;
01029   }  
01030   /**
01031    * Checks if a local variable is a reference.
01032    */
01033   public boolean isLocalVariableRef(int idx) {
01034     return top().isLocalVariableRef(idx);
01035   }  
01036   /**
01037    * Checks if the top operand is a reference.
01038    */
01039   public boolean isOperandRef() {
01040     return top().isOperandRef();
01041   }  
01042   /**
01043    * Checks if an operand is a reference.
01044    */
01045   public boolean isOperandRef(int idx) {
01046     return top().isOperandRef(idx);
01047   }  
01048   /**
01049    * Returns true if it is possible to execute the next instruction
01050    * of this thread. This function is used by the scheduler to determine
01051    * which threads can be executed.
01052    */
01053   public boolean isRunnable() {
01054     if(!isEnabled())
01055       return false;
01056 
01057     Instruction i = getPC();
01058 
01059     if(i == null) return false;
01060 
01061 //#ifdef CORINA
01062 
01063 
01064 
01065 
01066 
01067 
01068 
01069 
01070 
01071 //#endif CORINA
01072 
01073 //#ifdef COVERAGE
01074 
01075 
01076 
01077 
01078 //#endif COVERAGE
01079 
01080     // the instruction needs to be executable as well
01081     return i.isExecutable(list.ks.ss, list.ks, this);
01082   }  
01083   /**
01084    * Checks if the thread is safe. A thread is safe if its next
01085    * instruction is safe.
01086    */
01087   public boolean isSafe() {
01088     if(!isEnabled())
01089       return false;
01090 
01091     return top().isSafe();
01092   }  
01093   public boolean isThis(Reference r) {
01094     if(stack.length == 0) return false;
01095 
01096     return getMethod().isStatic() ?
01097       false :
01098       ((ElementInfo)r).index == getLocalVariable(0);
01099   }  
01100   /**
01101    * Leaves a soft atomic block.
01102    */
01103   public void leaveSoftAtomic() {
01104     atomicData.softAtomicLevel--;
01105   }  
01106   public void log() {
01107     Debug.println(Debug.MESSAGE, "TH#" + index + " #" + threadData.target + " #" + threadData.objref + " " + threadData.status);
01108     for(int i = 0; i < stack.length; i++)
01109       frame(i).log(i);
01110   }  
01111   /**
01112    * Peeks the top long value from the top stack frame.
01113    */
01114   public long longPeek() {
01115     return top().longPeek();
01116   }  
01117   /**
01118    * Peeks a long value from the top stack frame.
01119    */
01120   public long longPeek(int n) {
01121     return top().longPeek(n);
01122   }  
01123   /**
01124    * Pops the top long value from the top stack frame.
01125    */
01126   public long longPop() {
01127     return topClone().longPop();
01128   }  
01129   /**
01130    * Pushes a long value of the top stack frame.
01131    */
01132   public void longPush(long v) {
01133     topClone().longPush(v);
01134   }  
01135 //#ifdef MARK_N_SWEEP
01136   /**
01137    * Marks the objects referenced by the stack frames.
01138    */
01139   public void mark() {
01140     list.ks.da.mark(threadData.objref);
01141     if(threadData.target != -1) list.ks.da.mark(threadData.target);
01142 
01143     for(int i = 0, l = stack.length; i < l; i++)
01144       frame(i).mark(list.ks.da);
01145   }  
01146   /**
01147    * Adds a new stack frame for a new called method.
01148    */
01149   public void newFrame(MethodInfo mi) {
01150     StackFrame sf = new StackFrame(mi);
01151     if(sf.isSystemMethod())
01152       enterSoftAtomic();
01153 
01154     atomicData.inSameMethod = false;
01155 
01156     int depth = stack.length;
01157     StackFrame[] n = new StackFrame[depth + 1];
01158     System.arraycopy(stack, 0, n, 0, depth);
01159     stack = n;
01160 
01161     stack[depth] = sf;
01162 
01163     hasChanged.set(depth);
01164     anyChanged = true;
01165     list.ks.data = null;
01166     if(lowestChanged == -1 || lowestChanged > depth)
01167       lowestChanged = depth;
01168   }  
01169 //#endif MARK_N_SWEEP
01170 
01171   /**
01172    * Peeks the top value from the top stack frame.
01173    */
01174   public int peek() {
01175     return top().peek();
01176   }  
01177   /**
01178    * Peeks a value from the top stack frame.
01179    */
01180   public int peek(int n) {
01181     return top().peek(n);
01182   }  
01183   /**
01184    * Pops the top value from the top stack frame.
01185    */
01186   public int pop() {
01187     return topClone().pop();
01188   }  
01189   /**
01190    * Pops a set of values from the top stack frame.
01191    */
01192   public void pop(int n) {
01193     topClone().pop(n);
01194   }  
01195   /**
01196    * Removes a stack frame.
01197    */
01198   public void popFrame() {
01199     int last = stack.length - 1;
01200     StackFrame sf = stack[last];
01201 //#ifdef MARK_N_SWEEP
01202     if(sf.hasAnyRef())
01203       VirtualMachine.getSS().activateGC();
01204 //#endif MARK_N_SWEEP
01205 
01206 //#ifdef REFERENCE_COUNT
01207 
01208 //#endif REFERENCE_COUNT
01209 
01210     if(sf.isSystemMethod())
01211       leaveSoftAtomic();
01212 
01213     StackFrame[] n = new StackFrame[last];
01214     System.arraycopy(stack, 0, n, 0, last);
01215     stack = n;
01216 
01217     if(last == 0) {
01218       atomicData.inSameMethod = false;
01219       setStatus(STOPPED);
01220       list.ks.da.get(threadData.objref).notifies();
01221     } else
01222       atomicData.inSameMethod = getMethod() == atomicData.currentMethod;
01223 
01224     hasChanged.set(last);
01225     anyChanged = true;
01226     list.ks.data = null;
01227     if(lowestChanged == -1 || lowestChanged > last)
01228       lowestChanged = last;
01229   }  
01230   public void printInternalErrorTrace(Throwable e) {
01231     String msg = e.getMessage();
01232     if(msg != null)
01233       Debug.println(Debug.ERROR, "exception " + e.getClass().getName() + ": " + msg);
01234     else
01235       Debug.println(Debug.ERROR, "exception " + e.getClass().getName());
01236     printStackTrace();
01237     if(msg != null)
01238       Debug.println(Debug.ERROR, "exception " + e.getClass().getName() + ": " + msg);
01239     else
01240       Debug.println(Debug.ERROR, "exception " + e.getClass().getName());
01241     printStackContent();
01242   }  
01243   /**
01244    * Prints the content of the stack.
01245    */
01246   public void printStackContent() {
01247     for(int i = stack.length - 1; i >= 0; i--)
01248       frame(i).printStackContent();
01249   }  
01250   /**
01251    * Prints the trace of the stack.
01252    */
01253   public void printStackTrace() {
01254     for(int i = stack.length-1; i >= 0; i--)
01255       frame(i).printStackTrace();
01256   }  
01257   /**
01258    * Pushes a value on the top stack frame.
01259    */
01260   public void push(int v, boolean ref) {
01261     topClone().push(v, ref);
01262   }  
01263   /**
01264    * Removes the arguments of a method call.
01265    */
01266   public void removeArguments(MethodInfo mi) {
01267     int i = mi.getArgumentsSize();
01268 
01269     if(i != 0) pop(i);
01270   }  
01271   /**
01272    * Sets the value of a local variable.
01273    */
01274   public void setLocalVariable(int idx, int v, boolean ref) {
01275     topClone().setLocalVariable(idx, v, ref);
01276   }  
01277   /**
01278    * Sets the number of locks held at the time of a wait.
01279    */
01280   public void setLockCount(int l){
01281     if(threadData.lockCount != l)
01282       threadDataClone().lockCount = l;
01283   }  
01284   /**
01285    * Sets the value of a long local variable.
01286    */
01287   public void setLongLocalVariable(int idx, long v) {
01288     topClone().setLongLocalVariable(idx, v);
01289   }  
01290   /**
01291    * Sets the program counter of the top stack frame.
01292    */
01293   public void setPC(Instruction pc) {
01294     topClone().setPC(pc);
01295   }  
01296   private void setStackFrameIndex(int i, int idx) {
01297     if(hasChanged.get(i) || i+2 >= data.length || data[i+2] != idx)
01298       stack[i] = (StackFrame)stackFramePool.getObject(idx);
01299   }  
01300   /**
01301    * Updates the status of the thread.
01302    */
01303   public void setStatus(int s) {
01304     if(threadData.status != s)
01305       threadDataClone().status = s;
01306   }  
01307 //#ifdef RACE
01308 
01309 
01310 
01311 
01312 
01313 
01314 //#endif RACE
01315 
01316   /**
01317    * Sets the target of the thread.
01318    */
01319   public void setTarget(int t) {
01320     threadDataClone().target = t;
01321   }  
01322   private void setThreadDataIndex(int idx) {
01323     if(tdIndex == idx) return;
01324 
01325     tdIndex = idx;
01326     threadData = (ThreadData)threadDataPool.getObject(idx);
01327   }  
01328   /**
01329    * Swaps two entry on the stack.
01330    */
01331   public void swap() {
01332     topClone().swap();
01333   }  
01334   /**
01335    * Returns a clone of the thread data.
01336    */
01337   private ThreadData threadDataClone() {
01338     if(tdIndex == -1) return threadData;
01339 
01340     tdIndex = -1;
01341     list.ks.data = null;
01342     return threadData = (ThreadData)threadData.clone();
01343   }  
01344   /**
01345    * Throws an exception throught the stack frames.
01346    */
01347   public Instruction throwException(int objref) {
01348     ClassInfo ci = list.ks.da.get(objref).getClassInfo();
01349 
01350     while (countStackFrames() != 0) {
01351       MethodInfo mi = getMethod();
01352       ExceptionHandler[] exceptions = mi.getExceptions();
01353 
01354       if(exceptions != null) {
01355     int p = getPC().getPosition();
01356 
01357     // checks the exception catched in order
01358     for(int i = 0, s = exceptions.length; i < s; i++) {
01359       ExceptionHandler eh = exceptions[i];
01360 
01361       // if it falls in the right range
01362       if (p >= eh.getBegin() && p <= eh.getEnd()) {
01363         String en = eh.getName();
01364 
01365         // checks if this type of exception is caught here
01366         if(en == null || ci.instanceOf(en)) {
01367           // clears all the operand stack
01368           clearOperandStack();
01369 
01370           // pushes the exception on the stack instead
01371           push(objref, true);
01372 
01373           // jumps to the exception handler
01374           return mi.getInstructionAt(eh.getHandler());
01375         }
01376       }
01377     }
01378       }
01379 
01380       mi.leave(this);
01381 
01382       // remove a frame
01383       popFrame();
01384     }
01385 
01386     // no handler found
01387     setStatus(STOPPED);
01388     list.ks.da.get(threadData.objref).notifies();
01389     throw new UncaughtException(ci.getName());
01390   }  
01391   /**
01392    * Returns the top stack frame.
01393    */
01394   private StackFrame top() {
01395     return stack[stack.length-1];
01396   }  
01397   /**
01398    * Returns a clone of the top stack frame.
01399    */
01400   private StackFrame topClone() {
01401     int i = stack.length - 1;
01402     
01403     if(hasChanged.get(i)) return stack[i];
01404 
01405     hasChanged.set(i);
01406     anyChanged = true;
01407     list.ks.data = null;
01408     if(lowestChanged == -1 || lowestChanged > i)
01409       lowestChanged = i;
01410 
01411     return stack[i] = (StackFrame)stack[i].clone();
01412   }  
01413 }

Generated at Thu Feb 7 06:57:05 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001