Adding ParameterizedTypeImpl to getGenericSuperclass method.
[jpf-core.git] / src / main / gov / nasa / jpf / vm / ThreadInfo.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.vm;
19
20 import gov.nasa.jpf.vm.bytecode.ReturnInstruction;
21 import gov.nasa.jpf.Config;
22 import gov.nasa.jpf.JPF;
23 import gov.nasa.jpf.JPFException;
24 import gov.nasa.jpf.SystemAttribute;
25 import gov.nasa.jpf.jvm.bytecode.EXECUTENATIVE;
26 import gov.nasa.jpf.jvm.bytecode.INVOKESTATIC;
27 import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction;
28 import gov.nasa.jpf.util.HashData;
29 import gov.nasa.jpf.util.IntVector;
30 import gov.nasa.jpf.util.JPFLogger;
31 import gov.nasa.jpf.util.Predicate;
32 import gov.nasa.jpf.util.StringSetMatcher;
33 import gov.nasa.jpf.vm.choice.BreakGenerator;
34
35 import java.io.PrintWriter;
36 import java.io.File;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.HashMap;
40 import java.util.Iterator;
41 import java.util.LinkedList;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.NoSuchElementException;
45 import java.util.logging.Level;
46
47
48 /**
49  * Represents a thread. It contains the state of the thread, static
50  * information about the thread, and the stack frames.
51  * Race detection and lock order also store some information
52  * in this data structure.
53  *
54  * Note that we preserve identities according to their associated java.lang.Thread object
55  * (oref). This esp. means along the same path, a ThreadInfo reference
56  * is kept invariant
57  *
58  * <2do> remove EXECUTENATIVE,INVOKESTATIC .bytecode dependencies
59  */
60 public class ThreadInfo extends InfoObject
61      implements Iterable<StackFrame>, Comparable<ThreadInfo>, Restorable<ThreadInfo> {
62
63   static JPFLogger log = JPF.getLogger("gov.nasa.jpf.vm.ThreadInfo");
64   static int[] emptyLockRefs = new int[0];
65
66   //--- our internal thread states
67   public enum State {
68     NEW,  // means created but not yet started
69     RUNNING,
70     BLOCKED,  // waiting to acquire a lock
71     UNBLOCKED,  // was BLOCKED but can acquire the lock now
72     WAITING,  // waiting to be notified
73     TIMEOUT_WAITING,
74     NOTIFIED,  // was WAITING and got notified, but is still blocked
75     INTERRUPTED,  // was WAITING and got interrupted
76     TIMEDOUT,  // was TIMEOUT_WAITING and timed out
77     TERMINATED,
78     SLEEPING
79   };
80
81   static final int[] emptyRefArray = new int[0];
82   static final String MAIN_NAME = "main";
83   
84   
85   static ThreadInfo currentThread;
86
87   protected class StackIterator implements Iterator<StackFrame> {
88     StackFrame frame = top;
89
90     @Override
91         public boolean hasNext() {
92       return frame != null;
93     }
94
95     @Override
96         public StackFrame next() {
97       if (frame != null){
98         StackFrame ret = frame;
99         frame = frame.getPrevious();
100         return ret;
101
102       } else {
103         throw new NoSuchElementException();
104       }
105     }
106
107     @Override
108         public void remove() {
109       throw new UnsupportedOperationException("can't remove StackFrames");
110     }
111   }
112
113   protected class InvokedStackIterator extends StackIterator implements Iterator<StackFrame> {
114     InvokedStackIterator() {
115       frame = getLastInvokedStackFrame();
116     }
117
118     @Override
119         public StackFrame next() {
120       if (frame != null){
121         StackFrame ret = frame;
122         frame = null;
123         for (StackFrame f=ret.getPrevious(); f != null; f = f.getPrevious()){
124           if (!f.isDirectCallFrame()){
125             frame = f;
126             break;
127           }
128         }
129         return ret;
130
131       } else {
132         throw new NoSuchElementException();
133       }
134     }
135   }
136   
137   
138   //--- instance fields
139       
140   // transient, not state stored. This is reset when backtracking or starting a new transition
141   protected ExceptionInfo pendingException;
142
143   // state managed data that is copy-on-first-write
144   protected ThreadData threadData;
145
146   
147   //<2do> Hmm, why are these not in ThreadData?
148   // the top stack frame
149   protected StackFrame top = null;
150
151   // the current stack depth (number of frames)
152   protected int stackDepth;
153
154   
155   // something that tells the ThreadList how to look this up efficiently (e.g. index)
156   // note - this is for internal purposes only, there is no public accessor
157   // (we don't want to expose/hardwire ThreadList implementation)
158   // note also that the ThreadList is allowed to move this thread around, in which
159   // case update is the ThreadLists responsibility
160   protected int tlIdx;
161
162   
163   //--- the invariants
164
165   // we need this mostly for getting our SystemClassLoader
166   protected ApplicationContext appCtx;
167   
168   // search global id, which is the basis for canonical order of threads
169   protected int id;
170   
171   protected int objRef; // the java.lang.Thread object reference
172   protected ClassInfo ci; // the classinfo associated with the thread object
173   protected int targetRef; // the associated java.lang.Runnable
174   
175   // which attributes are stored/restored
176   static final int   ATTR_STORE_MASK = 0x0000ffff;
177
178   //--- the transient (un(re)stored) attributes
179   static final int ATTR_DATA_CHANGED       = 0x10000;
180   static final int ATTR_STACK_CHANGED      = 0x20000;
181   
182  // allow CG in next re-exec
183   static final int ATTR_ENABLE_EMPTY_TRANSITION = 0x4000;
184   
185   // don't call insn.execute()
186   static final int ATTR_SKIP_INSN_EXEC      = 0x100000;
187   
188   // don't store insn execution as transition step
189   static final int ATTR_SKIP_INSN_LOG       = 0x200000;
190   
191   
192   static final int ATTR_ATTRIBUTE_CHANGED  = 0x80000000;
193
194   //--- state stored/restored attributes  
195   // this is a typical "orthogonal" thread state we have to remember, but
196   // that should not affect any locking, blocking, notifying or such
197   static final int ATTR_STOPPED = 0x0001;
198
199   //--- change sets
200   static final int ATTR_ANY_CHANGED = (ATTR_DATA_CHANGED | ATTR_STACK_CHANGED | ATTR_ATTRIBUTE_CHANGED);
201   static final int ATTR_SET_STOPPED = (ATTR_STOPPED | ATTR_ATTRIBUTE_CHANGED);
202
203   protected int attributes;
204
205   
206   /** counter for executed instructions along current transition */
207   protected int executedInstructions;
208
209   /** a listener or peer request for throwing an exception into the SUT, to be processed in executeInstruction */
210   protected SUTExceptionRequest pendingSUTExceptionRequest;
211   
212   /** the last returned direct call frame */
213   protected DirectCallStackFrame returnedDirectCall;
214
215   /** the next insn to enter (null prior to execution) */
216   protected Instruction nextPc;
217
218   /**
219    * not so nice we cross-couple the NativePeers with ThreadInfo,
220    * but to carry on with the JNI analogy, a MJIEnv is clearly
221    * owned by a thread (even though we don't have much ThreadInfo
222    * state dependency in here (yet), hence the simplistic init)
223    */
224   MJIEnv env;
225
226   /**
227    * the VM we are running on. Bad backlink, but then again, we can't really
228    * test a ThreadInfo outside a VM context anyways.
229    * <2do> If we keep 'list' as a field, 'vm' might be moved over there
230    * (all threads in the list share the same VM)
231    */
232   VM vm;
233
234   /**
235    * !! this is a volatile object, i.e. it has to be re-computed explicitly
236    * !! after each backtrack (we don't want to duplicate state storage)
237    * list of lock objects currently held by this thread.
238    * unfortunately, we cannot organize this as a stack, since it might get
239    * restored (from the heap) in random order
240    */
241   int[] lockedObjectReferences;
242
243   /**
244    * !! this is also volatile -> has to be reset after backtrack
245    * the reference of the object if this thread is blocked or waiting for
246    */
247   int lockRef = MJIEnv.NULL;
248
249   Memento<ThreadInfo> cachedMemento; // cache for unchanged ThreadInfos
250
251
252   static class TiMemento implements Memento<ThreadInfo> {
253     // note that we don't have to store the invariants (id, oref, runnableRef, ciException)
254     ThreadInfo ti;
255
256     ThreadData threadData;
257     StackFrame top;
258     int stackDepth;
259     int attributes;
260
261     TiMemento (ThreadInfo ti){
262       this.ti = ti;
263       
264       threadData = ti.threadData;  // no need to clone - it's copy on first write
265       top = ti.top; // likewise
266       stackDepth = ti.stackDepth; // we just copy this for efficiency reasons
267       attributes = (ti.attributes & ATTR_STORE_MASK);
268
269       ti.freeze();
270       ti.markUnchanged();
271     }
272
273     @Override
274         public ThreadInfo restore(ThreadInfo ignored) {
275       ti.resetVolatiles();
276
277       ti.threadData = threadData;
278       ti.top = top;
279       ti.stackDepth = stackDepth;
280       ti.attributes = attributes;
281
282       ti.markUnchanged();
283
284       return ti;
285     }
286   }
287
288
289   // the following parameters are configurable. Would be nice if we could keep
290   // them on a per-instance basis, but there are a few locations
291   // (e.g. ThreadList) where we loose the init context, and it's questionable
292   // if we want to change this at runtime, or POR might make sense on a per-thread
293   // basis
294
295   /** do we halt on each throw, i.e. don't look for an exception handler?
296    * Useful to find empty handler blocks, or misusd exceptionHandlers
297    */
298   static StringSetMatcher haltOnThrow;
299
300   /**
301    * do we delegate to Thread.UncaughtExceptionHandlers (in case there is any
302    * other than the standard ThreadGroup)
303    */
304   static boolean ignoreUncaughtHandlers;
305   
306   /**
307    * do we go on if we return from an UncaughtExceptionHandler, or do we still
308    * regard this as a NoUncaughtExceptionProperty violation
309    */
310   static boolean passUncaughtHandler;
311
312   
313   /**
314    * break the current transition after this number of instructions.
315    * This is a safeguard against paths that won't break because potentially
316    * shared fields are not yet accessed by a second thread (existence of such
317    * paths is the downside of our access tracking). Note that we only break on
318    * backjumps once this count gets exceeded, to give state matching a better
319    * chance and avoid interference with the IdleLoop listener
320    */
321   static int maxTransitionLength;
322
323   /**
324    * reset ThreadInfo statics (e.g. to reinitialize JPF) 
325    */
326   static boolean init (Config config) {
327     currentThread = null;
328     
329     globalTids = new HashMap<Integer, Integer>();
330
331     String[] haltOnThrowSpecs = config.getStringArray("vm.halt_on_throw");
332     if (haltOnThrowSpecs != null){
333       haltOnThrow = new StringSetMatcher(haltOnThrowSpecs);
334     }
335     
336     ignoreUncaughtHandlers = config.getBoolean( "vm.ignore_uncaught_handler", true);
337     passUncaughtHandler = config.getBoolean( "vm.pass_uncaught_handler", true);
338
339     maxTransitionLength = config.getInt("vm.max_transition_length", 5000);
340
341     return true;
342   }
343     
344   //--- factory methods
345   // <2do> this is going to be a configurable factory method  
346   
347   /*
348    * search global cache for dense ThreadInfo ids. We could just use oref since those are
349    * guaranteed to be global, but not dense. The ids are search global, i.e. there is no
350    * need to store/restore, but it needs to be (re)set during init()  
351    */
352   static Map<Integer, Integer> globalTids;  // initialized by init
353   
354   
355   protected int computeId (int objRef) {
356     Integer id = globalTids.get(objRef);
357     
358     if(id == null) {
359       id = globalTids.size();
360       addId(objRef, id);
361     }
362
363     return id;
364   }
365
366   static void addId(int objRef, int id) {
367     globalTids.put(objRef, id);
368   }
369   
370   /**
371    * mainThread ctor called by the VM. Note we don't have a thread object yet (hen-and-egg problem
372    * since we can't allocate objects without a ThreadInfo)
373    */
374   protected ThreadInfo (VM vm, int id, ApplicationContext appCtx) {
375     this.id = id;
376     this.appCtx = appCtx;
377     
378     init(vm);
379     // we don't have the group yet, no Runnable or parent, and the name is fixed
380     // the thread is also not yet in the ThreadList
381     
382     ci = appCtx.getSystemClassLoader().getThreadClassInfo();
383     targetRef = MJIEnv.NULL;
384     threadData.name = MAIN_NAME;
385   }
386
387   /**
388    * the ctor for all explicitly (bytecode) created threads. At this point, there is at least
389    * a mainThread and we have a corresponding java.lang.Thread object
390    */
391   protected ThreadInfo (VM vm, int objRef, int groupRef, int runnableRef, int nameRef, ThreadInfo parent) {
392     id = computeId(objRef);
393     this.appCtx = parent.getApplicationContext();
394     
395     init(vm); // this is only partial, we still have to link/set the references
396     
397     ElementInfo ei = vm.getModifiableElementInfo(objRef);  
398     ei.setExposed(parent, null);        // all explicitly creatd threads are per se exposed
399     
400     this.ci = ei.getClassInfo();    
401     this.objRef = objRef;
402     this.targetRef = runnableRef;
403    
404     threadData.name = vm.getElementInfo(nameRef).asString();
405     
406     vm.getScheduler().initializeThreadSync(parent, this);
407     
408     // note the thread is not yet in the ThreadList, we have to register from the caller
409   }
410   
411   protected void init(VM vm){
412     // 'gid' is set by the factory method
413     // we can't set the 'id' field of the corresponding java.lang.Thread object until we have one
414     
415     this.vm = vm;
416
417     threadData = new ThreadData();
418     threadData.state = State.NEW;
419     threadData.priority = Thread.NORM_PRIORITY;
420     threadData.isDaemon = false;
421     threadData.lockCount = 0;
422     threadData.suspendCount = 0;
423     // threadData.name not yet known
424     
425     // 'priority', 'name', 'target' and 'group' are not taken
426     // from the object, but set within the java.lang.Thread ctors
427
428     top = null;
429     stackDepth = 0;
430
431     lockedObjectReferences = emptyLockRefs;
432
433     markUnchanged();
434     attributes |= ATTR_DATA_CHANGED; 
435     env = new MJIEnv(this);
436   }
437   
438   @Override
439   public Memento<ThreadInfo> getMemento(MementoFactory factory) {
440     return factory.getMemento(this);
441   }
442
443   public Memento<ThreadInfo> getMemento(){
444     return new TiMemento(this);
445   }
446   
447   void freeze() {
448     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()) {
449       frame.freeze();
450     }
451   }
452
453   //--- cached mementos are only supposed to be accessed from the Restorer
454
455   public Memento<ThreadInfo> getCachedMemento(){
456     return cachedMemento;
457   }
458
459   public void setCachedMemento(Memento<ThreadInfo> memento){
460     cachedMemento = memento;
461   }
462
463   public static ThreadInfo getCurrentThread() {
464     return currentThread;
465   }
466
467   public boolean isExecutingAtomically () {
468     return vm.getSystemState().isAtomic();
469   }
470
471   public boolean holdsLock (ElementInfo ei) {
472     int objRef = ei.getObjectRef();
473     
474     for (int i=0; i<lockedObjectReferences.length; i++) {
475       if (lockedObjectReferences[i] == objRef) {
476         return true;
477       }
478     }
479     
480     return false;
481   }
482
483   public VM getVM () {
484     return vm;
485   }
486
487   /**
488    * is *this* transition allowed to be empty (i.e. allowed to set a CG
489    * during re-execution of the current insn)
490    * reset before each instruction.execute()
491    */
492   public boolean isEmptyTransitionEnabled (){
493     return (attributes & ATTR_ENABLE_EMPTY_TRANSITION) != 0;
494   }
495   
496   public void enableEmptyTransition (){
497     attributes |= ATTR_ENABLE_EMPTY_TRANSITION;
498   }
499   
500   public void resetEmptyTransition(){
501     attributes &= ~ATTR_ENABLE_EMPTY_TRANSITION;
502   }
503   
504   /**
505    * answers if is this the first instruction within the current transition.
506    * This is mostly used to tell the top- from the bottom-half of a native method
507    * or Instruction.enter(), so that only one (the top half) registers the CG
508    * (top = register CG and reschedule insn, bottom = re-enter insn and process choice
509    * at beginning of new transition)
510    * 
511    * This can be used in both pre- and post-exec notification listeners, 
512    * the executedInstructions number is incremented before notifying
513    * instructionExecuted()
514    * 
515    * this method depends on the sequence of operations in ThreadInfo.executeInstruction,
516    * which is:
517    *   nextPc = null
518    *   notify executeInstruction
519    *   nextPc = insn.execute
520    *   increment executedInstructions
521    *   notify instructionExecuted
522    */
523   public boolean isFirstStepInsn() {
524     int nInsn = executedInstructions;
525     
526     if (nInsn == 0) {
527       // that would be a break in execute() or instructionExecuted()
528       return true;
529       
530     } else if (nInsn == 1 && nextPc != null) {
531       // that is for setting the CG in executeInsn and then testing in
532       // instructionExecuted. Note that nextPc is reset before pre-exec notification
533       // and hence should only be non-null from insn.execute() up to the next
534       // ThreadInfo.executeInstruction()
535       return true;
536     }
537     
538     return false;
539   }
540   
541   /**
542    * get the number of instructions executed in the current transition. This
543    * gets incremented after calling Instruction.enter(), i.e. before
544    * notifying instructionExecuted() listeners
545    */
546   public int getExecutedInstructions(){
547     return executedInstructions;
548   }
549   
550   /**
551    * to be used from methods called from listeners, to find out if we are in a
552    * pre- or post-exec notification
553    */
554   public boolean isPreExec() {
555     return (nextPc == null);
556   }
557
558
559   //--- various thread state related methods
560
561   /**
562    * Updates the status of the thread.
563    */
564   public void setState (State newStatus) {
565     State oldStatus = threadData.state;
566
567     if (oldStatus != newStatus) {
568
569       assert (oldStatus != State.TERMINATED) : "can't resurrect thread " + this + " to " + newStatus.name();
570
571       threadDataClone().state = newStatus;
572
573       switch (newStatus) {
574       case NEW:
575         break; // Hmm, shall we report a thread object creation?
576       case RUNNING:
577         // nothing. the notifyThreadStarted has to happen from
578         // Thread.start(), since the thread could have been blocked
579         // at the time with a sync run() method
580        // assert lockRef == MJIEnv.NULL;
581         break;
582       case TERMINATED:
583         vm.notifyThreadTerminated(this);
584         break;
585       case BLOCKED:
586         assert lockRef != MJIEnv.NULL;
587         vm.notifyThreadBlocked(this);
588         break;
589       case UNBLOCKED:
590         assert lockRef == MJIEnv.NULL;
591         break; // nothing to notify
592       case WAITING:
593         assert lockRef != MJIEnv.NULL;
594         vm.notifyThreadWaiting(this);
595         break;
596       case INTERRUPTED:
597         vm.notifyThreadInterrupted(this);
598         break;
599       case NOTIFIED:
600         assert lockRef != MJIEnv.NULL;
601         vm.notifyThreadNotified(this);
602         break;
603       }
604
605       if (log.isLoggable(Level.FINE)){
606         log.fine("setStatus of " + getName() + " from "
607                  + oldStatus.name() + " to " + newStatus.name());
608       }
609     }
610   }
611
612   void setBlockedState (int objref) {
613     
614     State currentState = threadData.state;
615     switch (currentState){
616       case NEW:
617       case RUNNING:
618       case UNBLOCKED:
619         lockRef = objref;
620         setState(State.BLOCKED);
621         break;
622
623       default:
624         assert false : "thread " + this + "can't be blocked in state: " + currentState.name();
625     }
626   }
627
628   void setNotifiedState() {
629     State currentState = threadData.state;
630     switch (currentState){
631       case BLOCKED:
632       case INTERRUPTED: // too late, we are already interrupted
633       case NOTIFIED:
634         // can happen in a Thread.join()
635         break;
636       case WAITING:
637       case TIMEOUT_WAITING:
638         setState(State.NOTIFIED);
639         break;
640
641       default:
642         assert false : "thread " + this + "can't be notified in state: " + currentState.name();
643     }
644   }
645
646   /**
647    * Returns the current status of the thread.
648    */
649   public State getState () {
650     return threadData.state;
651   }
652
653
654   /**
655    * Returns true if this thread is either RUNNING or UNBLOCKED
656    */
657   public boolean isRunnable () {
658     if (threadData.suspendCount != 0)
659       return false;
660
661     switch (threadData.state) {
662     case RUNNING:
663     case UNBLOCKED:
664       return true;
665     case SLEEPING:
666       return true;    // that's arguable, but since we don't model time we treat it like runnable
667     case TIMEDOUT:
668       return true;    // would have been set to blocked if it couldn't reacquire the lock
669     default:
670       return false;
671     }
672   }
673
674   public boolean willBeRunnable () {
675     if (threadData.suspendCount != 0)
676       return false;
677
678     switch (threadData.state) {
679     case RUNNING:
680     case UNBLOCKED:
681       return true;
682     case TIMEOUT_WAITING: // it's not yet, but it will be at the time it gets scheduled
683     case SLEEPING:
684       return true;
685     default:
686       return false;
687     }
688   }
689
690   public boolean isNew () {
691     return (threadData.state == State.NEW);
692   }
693
694   public boolean isTimeoutRunnable () {
695     if (threadData.suspendCount != 0)
696       return false;
697
698     switch (threadData.state) {
699
700     case RUNNING:
701     case UNBLOCKED:
702     case SLEEPING:
703       return true;
704
705     case TIMEOUT_WAITING:
706       // depends on if we can re-acquire the lock
707       //assert lockRef != MJIEnv.NULL : "timeout waiting but no blocked object";
708       if (lockRef != MJIEnv.NULL){
709         ElementInfo ei = vm.getElementInfo(lockRef);
710         return ei.canLock(this);
711       } else {
712         return true;
713       }
714
715     default:
716       return false;
717     }
718   }
719
720   public boolean isTimedOut() {
721     return (threadData.state == State.TIMEDOUT);
722   }
723
724   public boolean isTimeoutWaiting() {
725     return (threadData.state == State.TIMEOUT_WAITING);
726   }
727
728   public void setTimedOut() {
729     setState(State.TIMEDOUT);
730   }
731
732   public void setTerminated() {
733     setState(State.TERMINATED);
734   }
735
736   public void resetTimedOut() {
737     // should probably check for TIMEDOUT
738     setState(State.TIMEOUT_WAITING);
739   }
740
741   public void setSleeping() {
742     setState(State.SLEEPING);
743   }
744
745   public boolean isSleeping(){
746     return (threadData.state == State.SLEEPING);
747   }
748
749   public void setRunning() {
750     setState(State.RUNNING);
751   }
752
753   public void setStopped(int throwableRef){
754     if (isTerminated()){
755       // no need to kill twice
756       return;
757     }
758
759     attributes |= ATTR_SET_STOPPED;
760
761     if (!hasBeenStarted()){
762       // that one is easy - just remember the state so that a subsequent start()
763       // does nothing
764       return;
765     }
766
767     // for all other cases, we need to have a proper stopping Throwable that does not
768     // fall victim to GC, and that does not cause NoUncaughtExcceptionsProperty violations
769     if (throwableRef == MJIEnv.NULL){
770       // if no throwable was provided (the normal case), throw a java.lang.ThreadDeath Error
771       ClassInfo cix = ClassInfo.getInitializedSystemClassInfo("java.lang.ThreadDeath", this);
772       throwableRef = createException(cix, null, MJIEnv.NULL);
773     }
774
775     // now the tricky part - this thread is alive but might be blocked, notified
776     // or waiting. In any case, exception action should not take place before
777     // the thread becomes scheduled again, which
778     // means we are not allowed to fiddle with its state in any way that changes
779     // scheduling/locking behavior. On the other hand, if this is the currently
780     // executing thread, take immediate action
781
782     if (isCurrentThread()){ // we are suicidal
783       if (isInNativeMethod()){
784         // remember the exception to be thrown when we return from the native method
785         env.throwException(throwableRef);
786       } else {
787         Instruction nextPc = throwException(throwableRef);
788         setNextPC(nextPc);
789       }
790
791     } else { // this thread is not currently running, this is an external kill
792
793       // remember there was a pending exception that has to be thrown the next
794       // time this gets scheduled, and make sure the exception object does
795       // not get GCed prematurely
796       ElementInfo eit = getModifiableElementInfo(objRef);
797       eit.setReferenceField("stopException", throwableRef);
798     }
799   }
800
801   public boolean isCurrentThread(){
802     return this == currentThread;
803   }
804
805   public boolean isInCurrentThreadList(){
806     return vm.getThreadList().contains(this);
807   }
808   
809   /**
810    * An alive thread is anything but TERMINATED or NEW
811    */
812   public boolean isAlive () {
813     State state = threadData.state;
814     return (state != State.TERMINATED && state != State.NEW);
815   }
816
817   public boolean isWaiting () {
818     State state = threadData.state;
819     return (state == State.WAITING) || (state == State.TIMEOUT_WAITING);
820   }
821
822   public boolean isWaitingOrTimedOut (){
823     State state = threadData.state;
824     return (state == State.WAITING) || (state == State.TIMEOUT_WAITING) || (state == State.TIMEDOUT);
825   }
826
827   public boolean isNotified () {
828     return (threadData.state == State.NOTIFIED);
829   }
830
831   public boolean isUnblocked () {
832     State state = threadData.state;
833     return (state == State.UNBLOCKED) || (state == State.TIMEDOUT);
834   }
835
836   public boolean isBlocked () {
837     return (threadData.state == State.BLOCKED);
838   }
839
840   public boolean isTerminated () {
841     return (threadData.state == State.TERMINATED);
842   }
843
844   public boolean isAtomic (){
845     return vm.getSystemState().isAtomic();
846   }
847   
848   public void setBlockedInAtomicSection (){
849     vm.getSystemState().setBlockedInAtomicSection();
850   }
851   
852   MethodInfo getExitMethod() {
853     MethodInfo mi = getClassInfo().getMethod("exit()V", true);
854     return mi;
855   }
856
857   public boolean isBlockedOrNotified() {
858     State state = threadData.state;
859     return (state == State.BLOCKED) || (state == State.NOTIFIED);
860   }
861
862   // this is just a state attribute
863   public boolean isStopped() {
864     return (attributes & ATTR_STOPPED) != 0;
865   }
866
867   public boolean isInNativeMethod(){
868     return top != null && top.isNative();
869   }
870
871   public boolean hasBeenStarted(){
872     return (threadData.state != State.NEW);
873   }
874
875   public String getStateName () {
876     return threadData.getState().name();
877   }
878
879   @Override
880   public Iterator<StackFrame> iterator () {
881     return new StackIterator();
882   }
883
884   public Iterable<StackFrame> invokedStackFrames () {
885     return new Iterable<StackFrame>() {
886       @Override
887         public Iterator<StackFrame> iterator() {
888         return new InvokedStackIterator();
889       }
890     };
891   }
892
893   /**
894    * this returns a copy of the StackFrames in reverse order. Note this is
895    * redundant because the frames are linked explicitly
896    * @deprecated - use Iterable<StackFrame>
897    */
898   @Deprecated
899   public List<StackFrame> getStack() {
900     ArrayList<StackFrame> list = new ArrayList<StackFrame>(stackDepth);
901
902     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
903       list.add(frame);
904     }
905
906     Collections.reverse(list);
907
908     return list;
909   }
910
911   /**
912    * returns StackFrames which have been entered through a corresponding
913    * invoke instruction (in top first order)
914    */
915   public List<StackFrame> getInvokedStackFrames() {
916     ArrayList<StackFrame> list = new ArrayList<StackFrame>(stackDepth);
917
918     int i = stackDepth-1;
919     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
920       if (!frame.isDirectCallFrame()){
921         list.add( frame);
922       }
923     }
924     Collections.reverse(list);
925
926     return list;
927   }
928
929   public Scheduler getScheduler(){
930     return vm.getScheduler();
931   }
932   
933   public int getStackDepth() {
934     return stackDepth;
935   }
936   
937   public MethodInfo getEntryMethod(){    
938     return appCtx.getEntryMethod();
939   }
940
941   public StackFrame getCallerStackFrame (int offset){
942     int n = offset;
943     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
944       if (n < 0){
945         break;
946       } else if (n == 0){
947         return frame;
948       }
949       n--;
950     }
951     return null;
952   }
953
954   public StackFrame getLastInvokedStackFrame() {
955     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
956       if (!frame.isDirectCallFrame()){
957         return frame;
958       }
959     }
960
961     return null;
962   }
963
964   public StackFrame getLastNonSyntheticStackFrame (){
965     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
966       if (!frame.isSynthetic()){
967         return frame;
968       }
969     }
970
971     return null;
972   }
973   
974   // this is ugly - it can modify deeper stack frames
975   public StackFrame getModifiableLastNonSyntheticStackFrame (){
976     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
977       if (!frame.isSynthetic()){
978         if (frame.isFrozen()) {
979           StackFrame newFrame = frame.clone();
980           
981           if (frame == top) {
982             frame = newFrame;
983             top = newFrame;
984             
985           } else {
986             // Ughh, now we have to clone all frozen frames above
987             StackFrame fLast = null;
988             for (StackFrame f = getModifiableTopFrame(); f != frame; f = f
989                 .getPrevious()) {
990               if (f.isFrozen()) {
991                 f = f.clone();
992                 if (fLast != null) {
993                   fLast.setPrevious(f);
994                 }
995               }
996               fLast = f;
997             }
998             if (fLast != null) {
999               fLast.setPrevious(newFrame);
1000             }
1001
1002             frame = newFrame;
1003           }
1004         }
1005         
1006         return frame;
1007       }
1008     }
1009
1010     return null;
1011   }
1012   
1013
1014   /**
1015    * Returns the this pointer of the callee from the stack.
1016    */
1017   public int getCalleeThis (MethodInfo mi) {
1018     return top.getCalleeThis(mi);
1019   }
1020
1021   /**
1022    * Returns the this pointer of the callee from the stack.
1023    */
1024   public int getCalleeThis (int size) {
1025     return top.getCalleeThis(size);
1026   }
1027
1028   public ClassInfo getClassInfo (int objref) {
1029     return env.getClassInfo(objref);
1030   }
1031
1032   public boolean isCalleeThis (ElementInfo r) {
1033     if (top == null || r == null) {
1034       return false;
1035     }
1036
1037     Instruction pc = getPC();
1038
1039     if (pc == null ||
1040         !(pc instanceof JVMInvokeInstruction) ||
1041         pc instanceof INVOKESTATIC) {
1042       return false;
1043     }
1044
1045     JVMInvokeInstruction call = (JVMInvokeInstruction) pc;
1046
1047     return getCalleeThis(Types.getArgumentsSize(call.getInvokedMethodSignature()) + 1) == r.getObjectRef();
1048   }
1049
1050   public ApplicationContext getApplicationContext(){
1051     return appCtx;
1052   }
1053   
1054   public SystemClassLoaderInfo getSystemClassLoaderInfo(){
1055     return appCtx.sysCl;
1056   }
1057   
1058   /**
1059    * Returns the class information.
1060    */
1061   public ClassInfo getClassInfo () {
1062     return ci;
1063   }
1064
1065   public MJIEnv getEnv() {
1066     return env;
1067   }
1068
1069   public boolean isInterrupted (boolean resetStatus) {
1070     ElementInfo ei = getElementInfo(getThreadObjectRef());
1071     boolean status =  ei.getBooleanField("interrupted");
1072
1073     if (resetStatus && status) {
1074       ei = ei.getModifiableInstance();
1075       ei.setBooleanField("interrupted", false);
1076     }
1077
1078     return status;
1079   }
1080
1081   /**
1082    * path local unique id for live threads. This is what we use for the
1083    * public java.lang.Thread.getId() that can be called from SUT code. It is
1084    * NOT what we use for our canonical root set
1085    */
1086   public int getId () {
1087     return id;
1088   }
1089
1090   /**
1091    * this is our internal, search global id that is used for the
1092    * canonical root set
1093    */
1094   public int getGlobalId(){
1095     return id;
1096   }
1097   
1098   
1099   /**
1100    * record what this thread is being blocked on.
1101    */
1102   void setLockRef (int objref) {
1103 /**
1104     assert ((lockRef == MJIEnv.NULL) || (lockRef == objref)) :
1105       "attempt to overwrite lockRef: " + vm.getHeap().get(lockRef) +
1106       " with: " + vm.getHeap().get(objref);
1107 **/
1108     lockRef = objref;
1109   }
1110
1111   /**
1112    * thread is not blocked anymore
1113    * needs to be public since we have to use it from INVOKECLINIT (during call skipping)
1114    */
1115   public void resetLockRef () {
1116     lockRef = MJIEnv.NULL;
1117   }
1118
1119   public int getLockRef() {
1120     return lockRef;
1121   }
1122
1123   public ElementInfo getLockObject () {
1124     if (lockRef == MJIEnv.NULL) {
1125       return null;
1126     } else {
1127       return vm.getElementInfo(lockRef);
1128     }
1129   }
1130
1131   /**
1132    * Returns the line number of the program counter of the top stack frame.
1133    */
1134   public int getLine () {
1135     if (top == null) {
1136       return -1;
1137     } else {
1138       return top.getLine();
1139     }
1140   }
1141   
1142   //--- suspend/resume modeling
1143   // modeling this with a count is an approximation. In reality it behaves
1144   // rather like a race that /sometimes/ causes the resume to fail, but its
1145   // Ok if we overapproximate on the safe side, since suspend/resume is such
1146   // an inherently unsafe thing. What we *do* want to preserve faithfully is 
1147   // that locks held by the suspended thread are not released
1148   
1149   /**
1150    * set suspension status
1151    * @return true if thread was not suspended
1152    */
1153   public boolean suspend() {
1154     return threadDataClone().suspendCount++ == 0;
1155   }
1156
1157   /**
1158    * unset suspension status
1159    * @return true if thread was suspended
1160    */
1161   public boolean resume() {
1162     return (threadData.suspendCount > 0) && (--threadDataClone().suspendCount == 0);
1163   }
1164   
1165   public boolean isSuspended() {
1166     return threadData.suspendCount > 0;
1167   }
1168
1169
1170   //--- locks
1171   
1172   /**
1173    * Sets the number of locks held at the time of a wait.
1174    */
1175   public void setLockCount (int l) {
1176     if (threadData.lockCount != l) {
1177       threadDataClone().lockCount = l;
1178     }
1179   }
1180
1181   /**
1182    * Returns the number of locks in the last wait.
1183    */
1184   public int getLockCount () {
1185     return threadData.lockCount;
1186   }
1187
1188   // avoid use in performance critical code
1189   public List<ElementInfo> getLockedObjects () {
1190     List<ElementInfo> lockedObjects = new LinkedList<ElementInfo>();
1191     Heap heap = vm.getHeap();
1192     
1193     for (int i=0; i<lockedObjectReferences.length; i++) {
1194       ElementInfo ei = heap.get(lockedObjectReferences[i]);
1195       lockedObjects.add(ei);
1196     }
1197     
1198     return lockedObjects;
1199   }
1200
1201   public boolean hasLockedObjects() {
1202     return lockedObjectReferences.length > 0;
1203   }
1204   
1205   public int[] getLockedObjectReferences () {
1206     return lockedObjectReferences;
1207   }
1208
1209   public boolean isLockOwner (ElementInfo ei){
1210     return ei.getLockingThread() == this;
1211   }
1212   
1213   /**
1214    * returns the current method in the top stack frame, which is always a
1215    * bytecode method (executed by JPF)
1216    */
1217   public MethodInfo getTopFrameMethodInfo () {
1218     if (top != null) {
1219       return top.getMethodInfo();
1220     } else {
1221       return null;
1222     }
1223   }
1224
1225   /**
1226    * return the ClassInfo of the topmost stackframe that is not a direct call 
1227    */
1228   public ClassInfo getExecutingClassInfo(){
1229     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
1230       MethodInfo miExecuting = frame.getMethodInfo();
1231       ClassInfo ciExecuting = miExecuting.getClassInfo();
1232       if (ciExecuting != null){
1233         return ciExecuting;
1234       }
1235     }
1236     
1237     return null;
1238   }
1239   
1240   
1241   
1242   public ClassInfo resolveReferencedClass (String clsName){
1243     ClassInfo ciTop = top.getClassInfo();
1244     return ciTop.resolveReferencedClass(clsName);
1245             
1246     //return ClassLoaderInfo.getCurrentClassLoader(this).getResolvedClassInfo(clsName);
1247   }
1248   
1249   public boolean isInCtor () {
1250     // <2do> - hmm, if we don't do this the whole stack, we miss factored
1251     // init funcs
1252     MethodInfo mi = getTopFrameMethodInfo();
1253     if (mi != null) {
1254       return mi.isCtor();
1255     } else {
1256       return false;
1257     }
1258   }
1259
1260   public boolean isCtorOnStack (int objRef){
1261     for (StackFrame f = top; f != null; f = f.getPrevious()){
1262       if (f.getThis() == objRef && f.getMethodInfo().isCtor()){
1263         return true;
1264       }
1265     }
1266
1267     return false;
1268   }
1269
1270   public boolean isClinitOnStack (ClassInfo ci){
1271     for (StackFrame f = top; f != null; f = f.getPrevious()){
1272       MethodInfo mi = f.getMethodInfo();
1273       if (mi.isClinit(ci)){
1274         return true;
1275       }
1276     }
1277
1278     return false;
1279   }
1280
1281
1282   public String getName () {
1283     return threadData.name;
1284   }
1285
1286
1287
1288   /**
1289    * Returns the object reference.
1290    */
1291   public int getThreadObjectRef () {
1292     return objRef;
1293   }
1294
1295   public ElementInfo getThreadObject(){
1296     return getElementInfo(objRef);
1297   }
1298
1299   public ElementInfo getModifiableThreadObject() {
1300     return getModifiableElementInfo(objRef);
1301   }
1302   
1303
1304   /**
1305    * Sets the program counter of the top stack frame.
1306    */
1307   public void setPC (Instruction pc) {
1308     getModifiableTopFrame().setPC(pc);
1309   }
1310
1311   public void advancePC () {
1312     getModifiableTopFrame().advancePC();
1313   }
1314
1315   /**
1316    * Returns the program counter of the top stack frame.
1317    */
1318   public Instruction getPC () {
1319     if (top != null) {
1320       return top.getPC();
1321     } else {
1322       return null;
1323     }
1324   }
1325
1326   public Instruction getNextPC () {
1327     return nextPc;
1328   }
1329
1330
1331   /**
1332    * get the current stack trace of this thread
1333    * this is called during creation of a Throwable, hence we should skip
1334    * all throwable ctors in here
1335    * <2do> this is only a partial solution,since we don't catch exceptionHandlers
1336    * in Throwable ctors yet
1337    */
1338   public String getStackTrace () {
1339     StringBuilder sb = new StringBuilder(256);
1340
1341     for (StackFrame sf = top; sf != null; sf = sf.getPrevious()){
1342       MethodInfo mi = sf.getMethodInfo();
1343
1344       if (mi.isCtor()){
1345         ClassInfo ci = mi.getClassInfo();
1346         if (ci.isInstanceOf("java.lang.Throwable")) {
1347           continue;
1348         }
1349       }
1350
1351       sb.append("\tat ");
1352       sb.append(sf.getStackTraceInfo());
1353       sb.append('\n');
1354     }
1355
1356     return sb.toString();
1357   }
1358
1359
1360   /**
1361    * Returns the information necessary to store.
1362    *
1363    * <2do> pcm - not clear to me how lower stack frames can contribute to
1364    * a different threadinfo state hash - only the current one can be changed
1365    * by the executing method
1366    */
1367   public void dumpStoringData (IntVector v) {
1368     v = null;  // Get rid of IDE warnings
1369   }
1370
1371   /**
1372    * Returns the object reference of the target.
1373    */
1374   public int getRunnableRef () {
1375     return targetRef;
1376   }
1377
1378   /**
1379    * Returns the pointer to the object reference of the executing method
1380    */
1381   public int getThis () {
1382     return top.getThis();
1383   }
1384
1385   public ElementInfo getThisElementInfo(){
1386     return getElementInfo(getThis());
1387   }
1388
1389   public boolean isThis (ElementInfo ei) {
1390     if (ei == null) {
1391       return false;
1392     }
1393
1394     if (top == null) {
1395       return false;
1396     }
1397
1398     if (getTopFrameMethodInfo().isStatic()) {
1399       return false;
1400     } else {
1401       int thisRef = top.getThis();
1402       return ei.getObjectRef() == thisRef;
1403     }
1404   }
1405
1406   public boolean atMethod (String mname) {
1407     return top != null && getTopFrameMethodInfo().getFullName().equals(mname);
1408   }
1409
1410   public boolean atPosition (int position) {
1411     if (top == null) {
1412       return false;
1413     } else {
1414       Instruction pc = getPC();
1415       return pc != null && pc.getPosition() == position;
1416     }
1417   }
1418
1419   public boolean atReturn () {
1420     if (top == null) {
1421       return false;
1422     } else {
1423       Instruction pc = getPC();
1424       return pc instanceof ReturnInstruction;
1425     }
1426   }
1427
1428
1429   /**
1430    * reset any information that has to be re-computed in a backtrack
1431    * (i.e. hasn't been stored explicitly)
1432    */
1433   void resetVolatiles () {
1434     // resetting lock sets goes here
1435     lockedObjectReferences = emptyLockRefs;
1436
1437     // the ref of the object we are blocked on or waiting for
1438     lockRef = MJIEnv.NULL;
1439
1440     pendingException = null;
1441   }
1442   
1443   /**
1444    * this is used when restoring states
1445    */
1446   void updateLockedObject (ElementInfo ei) {
1447     int n = lockedObjectReferences.length;    
1448     int[] a = new int[n+1];
1449     System.arraycopy(lockedObjectReferences, 0, a, 0, n);
1450     a[n] = ei.getObjectRef();
1451     lockedObjectReferences = a;
1452     
1453     // don't notify here, it's just a restore
1454   }
1455
1456   void addLockedObject (ElementInfo ei) {
1457     int n = lockedObjectReferences.length;    
1458     int[] a = new int[n+1];
1459     System.arraycopy(lockedObjectReferences, 0, a, 0, n);
1460     a[n] = ei.getObjectRef();
1461     lockedObjectReferences = a;
1462     
1463     vm.notifyObjectLocked(this, ei);
1464   }
1465
1466   void removeLockedObject (ElementInfo ei) {
1467     int objRef = ei.getObjectRef();
1468     int n = lockedObjectReferences.length;
1469     
1470     if (n == 1) {
1471       assert lockedObjectReferences[0] == objRef;
1472       lockedObjectReferences = emptyLockRefs;
1473       
1474     } else {
1475       int[] a = new int[n - 1];
1476
1477       for (int i = 0, j = 0; i < n; i++) {
1478         if (lockedObjectReferences[i] != objRef) {
1479           a[j++] = lockedObjectReferences[i];
1480         }
1481       }
1482       lockedObjectReferences = a;
1483     }
1484     
1485     vm.notifyObjectUnlocked(this, ei);
1486   }
1487
1488
1489   @Override
1490   public Object clone() {
1491     try {
1492       // threadData and top StackFrame are copy-on-write, so we should not have to clone them
1493       // lockedObjects are state-volatile and restored explicitly after a backtrack
1494       return super.clone();
1495
1496     } catch (CloneNotSupportedException cnsx) {
1497       return null;
1498     }
1499   }
1500
1501   /**
1502    * Returns the number of stack frames.
1503    */
1504   public int countStackFrames () {
1505     return stackDepth;
1506   }
1507
1508   /**
1509    * get a stack snapshot that consists of an array of {mthId,pc} pairs.
1510    * strip stackframes that enter instance methods of the exception object
1511    */
1512   public int[] getSnapshot (int xObjRef) {
1513     StackFrame frame = top;
1514     int n = stackDepth;
1515     
1516     if (xObjRef != MJIEnv.NULL){ // filter out exception method frames
1517       for (;frame != null; frame = frame.getPrevious()){
1518         if (frame.getThis() != xObjRef){
1519           break;
1520         }
1521         n--;
1522       }
1523     }
1524
1525     int j=0;
1526     int[] snap = new int[n*2];
1527
1528     for (; frame != null; frame = frame.getPrevious()){
1529       snap[j++] = frame.getMethodInfo().getGlobalId();
1530       snap[j++] = frame.getPC().getInstructionIndex();
1531     }
1532
1533     return snap;
1534   }
1535
1536   /**
1537    * turn a snapshot into an JPF array of StackTraceElements, which means
1538    * a lot of objects. Do this only on demand
1539    */
1540   public int createStackTraceElements (int[] snapshot) {
1541     int n = snapshot.length/2;
1542     int nVisible=0;
1543     StackTraceElement[] list = new StackTraceElement[n];
1544     for (int i=0, j=0; i<n; i++){
1545       int methodId = snapshot[j++];
1546       int pcOffset = snapshot[j++];
1547       StackTraceElement ste = new StackTraceElement( methodId, pcOffset);
1548       if (!ste.ignore){
1549         list[nVisible++] = ste;
1550       }
1551     }
1552
1553     Heap heap = vm.getHeap();
1554     ElementInfo eiArray = heap.newArray("Ljava/lang/StackTraceElement;", nVisible, this);
1555     for (int i=0; i<nVisible; i++){
1556       int eref = list[i].createJPFStackTraceElement();
1557       eiArray.setReferenceElement( i, eref);
1558     }
1559
1560     return eiArray.getObjectRef();
1561   }
1562
1563   void print (PrintWriter pw, String s) {
1564     if (pw != null){
1565       pw.print(s);
1566     } else {
1567       vm.print(s);
1568     }
1569   }
1570
1571   public void printStackTrace (int objRef) {
1572     printStackTrace(null, objRef);
1573   }
1574
1575   public void printPendingExceptionOn (PrintWriter pw) {
1576     if (pendingException != null) {
1577       printStackTrace( pw, pendingException.getExceptionReference());
1578     }
1579   }
1580
1581   /**
1582    * the reason why this is kind of duplicated (there is also a StackFrame.getPositionInfo)
1583    * is that this might be working off a StackTraceElement[] that is created when the exception
1584    * is created. At the time printStackTrace() is called, the StackFrames in question
1585    * are most likely already be unwinded
1586    */
1587   public void printStackTrace (PrintWriter pw, int objRef) {
1588     // 'env' usage is not ideal, since we don't know from what context we are called, and
1589     // hence the MJIEnv calling context might not be set (no Method or ClassInfo)
1590     // on the other hand, we don't want to re-implement all the MJIEnv accessor methods
1591
1592     print(pw, env.getClassInfo(objRef).getName());
1593     int msgRef = env.getReferenceField(objRef,"detailMessage");
1594     if (msgRef != MJIEnv.NULL) {
1595       print(pw, ": ");
1596       print(pw, env.getStringObject(msgRef));
1597     }
1598     print(pw, "\n");
1599
1600     // try the 'stackTrace' field first, it might have been set explicitly
1601     int aRef = env.getReferenceField(objRef, "stackTrace"); // StackTrace[]
1602     if (aRef != MJIEnv.NULL) {
1603       int len = env.getArrayLength(aRef);
1604       for (int i=0; i<len; i++) {
1605         int steRef = env.getReferenceArrayElement(aRef, i);
1606         if (steRef != MJIEnv.NULL){  // might be ignored (e.g. direct call)
1607           StackTraceElement ste = new StackTraceElement(steRef);
1608           ste.printOn( pw);
1609         }
1610       }
1611
1612     } else { // fall back to use the snapshot stored in the exception object
1613       aRef = env.getReferenceField(objRef, "snapshot");
1614       int[] snapshot = env.getIntArrayObject(aRef);
1615       int len = snapshot.length/2;
1616
1617       for (int i=0, j=0; i<len; i++){
1618         int methodId = snapshot[j++];
1619         int pcOffset = snapshot[j++];
1620         StackTraceElement ste = new StackTraceElement( methodId, pcOffset);
1621         ste.printOn( pw);
1622       }
1623     }
1624
1625     int causeRef = env.getReferenceField(objRef, "cause");
1626     if ((causeRef != objRef) && (causeRef != MJIEnv.NULL)){
1627       print(pw, "Caused by: ");
1628       printStackTrace(pw, causeRef);
1629     }
1630   }
1631
1632   class StackTraceElement {
1633     String clsName, mthName, fileName;
1634     int line;
1635     boolean ignore;
1636
1637
1638     StackTraceElement (int methodId, int pcOffset) {
1639       if (methodId == MethodInfo.DIRECT_CALL) {
1640         ignore = true;
1641
1642       } else {
1643         MethodInfo mi = MethodInfo.getMethodInfo(methodId);
1644         if (mi != null) {
1645           clsName = mi.getClassName();
1646           mthName = mi.getName();
1647
1648           fileName = mi.getStackTraceSource();          
1649           if (pcOffset < 0){
1650             // See ThreadStopTest.threadDeathWhileRunstart
1651             // <2do> remove when RUNSTART is gone
1652             pcOffset = 0;
1653           }
1654           line = mi.getLineNumber(mi.getInstruction(pcOffset));
1655
1656         } else { // this sounds like a bug
1657           clsName = "?";
1658           mthName = "?";
1659           fileName = "?";
1660           line = -1;
1661         }
1662       }
1663     }
1664
1665     StackTraceElement (int sRef){
1666       clsName = env.getStringObject(env.getReferenceField(sRef, "clsName"));
1667       mthName = env.getStringObject(env.getReferenceField(sRef, "mthName"));
1668       fileName = env.getStringObject(env.getReferenceField(sRef, "fileName"));
1669       line = env.getIntField(sRef, "line");
1670     }
1671
1672     int createJPFStackTraceElement() {
1673       if (ignore) {
1674         return MJIEnv.NULL;
1675         
1676       } else {
1677         Heap heap = vm.getHeap();
1678         ClassInfo ci = ClassLoaderInfo.getSystemResolvedClassInfo("java.lang.StackTraceElement");
1679         ElementInfo ei = heap.newObject(ci, ThreadInfo.this);
1680
1681         ei.setReferenceField("clsName", heap.newString(clsName, ThreadInfo.this).getObjectRef());
1682         ei.setReferenceField("mthName", heap.newString(mthName, ThreadInfo.this).getObjectRef());
1683
1684         String fname = fileName != null ? fileName : "Unknown Source";
1685         ei.setReferenceField("fileName", heap.newString(fname, ThreadInfo.this).getObjectRef());
1686                 
1687         ei.setIntField("line", line);
1688
1689         return ei.getObjectRef();
1690       }
1691     }
1692
1693     void printOn (PrintWriter pw){
1694       if (!ignore){
1695         // the usual behavior is to print only the filename, strip the path
1696         if (fileName != null){
1697           int idx = fileName.lastIndexOf(File.separatorChar);
1698           if (idx >=0) {
1699             fileName = fileName.substring(idx+1);
1700           }
1701         }
1702
1703         print(pw, "\tat ");
1704         if (clsName != null){
1705           print(pw, clsName);
1706           print(pw, ".");
1707         } else { // some synthetic methods don't belong to classes
1708           print(pw, "[no class] ");
1709         }
1710         print(pw, mthName);
1711
1712         if (fileName != null){
1713           print(pw, "(");
1714           print(pw, fileName);
1715           if (line >= 0){
1716             print(pw, ":");
1717             print(pw, Integer.toString(line));
1718           }
1719           print(pw, ")");
1720         } else {
1721           //print(pw, "<no source>");
1722         }
1723
1724         print(pw, "\n");
1725       }
1726     }
1727   }
1728
1729   /**
1730    * this is a helper class to store listener generated exception requests that are checked before and after
1731    * calling Instruction.execute(). This is a safe way to raise SUT exceptions from listener code without compromising
1732    * consistency of executes() that are not prepared to cut short by means of re-execution or host VM exceptions
1733    */
1734   static class SUTExceptionRequest {
1735     String xClsName;
1736     String details;
1737     
1738     SUTExceptionRequest (String xClsName, String details){
1739       this.xClsName = xClsName;
1740       this.details = details;
1741     }
1742     
1743     public String getExceptionClassName(){
1744       return xClsName;
1745     }
1746     
1747     public String getDetails(){
1748       return details;
1749     }
1750   }
1751   
1752   public void requestSUTException (String exceptionClsName, String details){
1753     pendingSUTExceptionRequest = new SUTExceptionRequest( exceptionClsName, details);
1754     if (nextPc == null){ // this is pre-exec, skip the execute()
1755       attributes |= ATTR_SKIP_INSN_EXEC;
1756     }
1757   }
1758   
1759   protected void processPendingSUTExceptionRequest (){
1760     if (pendingSUTExceptionRequest != null){
1761       // <2do> we could do more specific checks for ClassNotFoundExceptions here
1762       nextPc = createAndThrowException( pendingSUTExceptionRequest.getExceptionClassName(), pendingSUTExceptionRequest.getDetails());
1763       pendingSUTExceptionRequest = null;
1764     }
1765   }
1766   
1767   
1768   /**
1769    * <2do> pcm - this is only valid for java.* and our own Throwables that don't
1770    * need ctor execution since we only initializeSharednessPolicy the Throwable fields. This method
1771    * is here to avoid round trips in case of exceptions
1772    */
1773   int createException (ClassInfo ci, String details, int causeRef){
1774     int[] snap = getSnapshot(MJIEnv.NULL);
1775     return vm.getHeap().newSystemThrowable(ci, details, snap, causeRef, this, 0).getObjectRef();
1776   }
1777
1778   /**
1779    * Creates and throws an exception. This is what is used if the exception is
1780    * thrown by the VM (or a listener)
1781    */
1782   public Instruction createAndThrowException (ClassInfo ci, String details) {
1783     //if (ci.initializeClass(this)) {
1784     //  return getPC();
1785     //}
1786     ci.initializeClassAtomic(this);
1787
1788     int objref = createException(ci,details, MJIEnv.NULL);
1789     return throwException(objref);
1790   }
1791
1792   /**
1793    * Creates an exception and throws it.
1794    */
1795   public Instruction createAndThrowException (String cname) {
1796     return createAndThrowException(cname, null);
1797   }
1798
1799   public Instruction createAndThrowException (String cname, String details) {
1800     try {
1801       ClassInfo ci = null;
1802       try {
1803         ci = ClassLoaderInfo.getCurrentResolvedClassInfo(cname);
1804       } catch(ClassInfoException cie) {
1805         // the non-system class loader couldn't find the class, 
1806         if(cie.getExceptionClass().equals("java.lang.ClassNotFoundException") &&
1807                         !ClassLoaderInfo.getCurrentClassLoader().isSystemClassLoader()) {
1808           ci = ClassLoaderInfo.getSystemResolvedClassInfo(cname);
1809         } else {
1810           throw cie;
1811         }
1812       }
1813       return createAndThrowException(ci, details);
1814       
1815     } catch (ClassInfoException cie){
1816       if(!cname.equals(cie.getExceptionClass())) {
1817         ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(cie.getExceptionClass());
1818         return createAndThrowException(ci, cie.getMessage());
1819       } else {
1820         throw cie;
1821       }
1822     }
1823   }
1824
1825   /**
1826    * can be used by instructions to break long transitions (preferably on 
1827    * backjumps so that state matching could terminate the search)
1828    */
1829   public boolean maxTransitionLengthExceeded(){
1830     return executedInstructions >= maxTransitionLength;
1831   }
1832   
1833   /**
1834    * enter instructions until there is none left or somebody breaks
1835    * the transition (e.g. by registering a CG)
1836    * 
1837    * this is the inner interpreter loop of JPF
1838    */
1839   protected void executeTransition (SystemState ss) throws JPFException {
1840     Instruction pc;
1841     outer:
1842     while ((pc = getPC()) != null){
1843       Instruction nextPc = null;
1844
1845       currentThread = this;
1846       executedInstructions = 0;
1847       pendingException = null;
1848
1849       if (isStopped()){
1850         pc = throwStopException();
1851         setPC(pc);
1852       }
1853
1854       // this constitutes the main transition loop. It gobbles up
1855       // insns until someone registered a ChoiceGenerator, there are no insns left,
1856       // the transition was explicitly marked as ignored, or we have reached a
1857       // max insn count and preempt the thread upon the next available backjump
1858       while (pc != null) {
1859         nextPc = executeInstruction();
1860
1861         if (ss.breakTransition()) {
1862           if (ss.extendTransition()){
1863             continue outer;
1864             
1865           } else {
1866             if (executedInstructions == 0){ // a CG from a re-executed insn
1867               if (isEmptyTransitionEnabled()){ // treat as a new state if empty transitions are enabled
1868                 ss.setForced(true);
1869               }
1870             }
1871             return;
1872           }
1873
1874         } else {        
1875           pc = nextPc;
1876         }
1877       }
1878     }
1879   }
1880
1881
1882   protected void resetTransientAttributes(){
1883     attributes &= ~(ATTR_SKIP_INSN_EXEC | ATTR_SKIP_INSN_LOG | ATTR_ENABLE_EMPTY_TRANSITION);
1884   }
1885   
1886   /**
1887    * Execute next instruction.
1888    */
1889   public Instruction executeInstruction () {
1890     Instruction pc = getPC();
1891     SystemState ss = vm.getSystemState();
1892
1893     resetTransientAttributes();
1894     nextPc = null;
1895     
1896     // note that we don't reset pendingSUTExceptionRequest since it could be set outside executeInstruction()
1897     
1898     if (log.isLoggable(Level.FINER)) {
1899       log.fine( pc.getMethodInfo().getFullName() + " " + pc.getPosition() + " : " + pc);
1900     }
1901
1902     // this is the pre-execution notification, during which a listener can perform
1903     // on-the-fly instrumentation or even replace the instruction alltogether
1904     vm.notifyExecuteInstruction(this, pc);
1905
1906     if ((pendingSUTExceptionRequest == null) && ((attributes & ATTR_SKIP_INSN_EXEC) == 0)){
1907         try {
1908           nextPc = pc.execute(this);
1909         } catch (ClassInfoException cie) {
1910           nextPc = this.createAndThrowException(cie.getExceptionClass(), cie.getMessage());
1911         }
1912       }
1913
1914     // we also count the skipped ones
1915     executedInstructions++;
1916     
1917     if ((attributes & ATTR_SKIP_INSN_LOG) == 0) {
1918       ss.recordExecutionStep(pc);
1919     }
1920
1921     // here we have our post exec bytecode exec observation point
1922     vm.notifyInstructionExecuted(this, pc, nextPc);
1923     
1924     // since this is part of the inner execution loop, it is a convenient place to check for probes
1925     vm.getSearch().checkAndResetProbeRequest();
1926     
1927     // clean up whatever might have been stored by enter
1928     pc.cleanupTransients();
1929
1930     if (pendingSUTExceptionRequest != null){
1931       processPendingSUTExceptionRequest();
1932     }
1933     
1934     // set+return the next insn to enter if we did not return from the last stack frame.
1935     // Note that 'nextPc' might have been set by a listener, and/or 'top' might have
1936     // been changed by executing an invoke, return or throw (handler), or by
1937     // pushing overlay calls on the stack
1938     if (top != null) {
1939       // <2do> this is where we would have to handle general insn repeat
1940       setPC(nextPc);
1941       return nextPc;
1942     } else {
1943       return null;
1944     }
1945   }
1946
1947   /**
1948    * enter instruction hidden from any listeners, and do not
1949    * record it in the path
1950    */
1951   public Instruction executeInstructionHidden () {
1952     Instruction pc = getPC();
1953     SystemState ss = vm.getSystemState();
1954     KernelState ks = vm.getKernelState();
1955
1956     nextPc = null; // reset in case pc.execute() blows (this could be behind an exception firewall)
1957
1958     if (log.isLoggable(Level.FINE)) {
1959       log.fine( pc.getMethodInfo().getFullName() + " " + pc.getPosition() + " : " + pc);
1960     }
1961
1962     try {
1963         nextPc = pc.execute(this);
1964       } catch (ClassInfoException cie) {
1965         nextPc = this.createAndThrowException(cie.getExceptionClass(), cie.getMessage());
1966       }
1967
1968     // we also count the hidden ones since isFirstStepInsn depends on it
1969     executedInstructions++;
1970     
1971     // since this is part of the inner execution loop, it is a convenient place  to check probe notifications
1972     vm.getSearch().checkAndResetProbeRequest();
1973     
1974     // we did not return from the last frame stack
1975     if (top != null) { // <2do> should probably bomb otherwise
1976       setPC(nextPc);
1977     }
1978
1979     return nextPc;
1980   }
1981
1982   /**
1983    * is this after calling Instruction.enter()
1984    * used by instructions and listeners
1985    */
1986   public boolean isPostExec() {
1987     return (nextPc != null);
1988   }
1989
1990   public void reExecuteInstruction() {
1991     nextPc = getPC();
1992   }
1993
1994   public boolean willReExecuteInstruction() {
1995     return (getPC() == nextPc);
1996   }
1997   
1998   /**
1999    * skip the next bytecode. To be used by listeners to on-the-fly replace
2000    * instructions
2001    */
2002   public void skipInstruction (Instruction nextInsn) {
2003     attributes |= ATTR_SKIP_INSN_EXEC;
2004     
2005     //assert nextInsn != null;
2006     nextPc = nextInsn;
2007   }
2008
2009   /**
2010    * skip and continue with the following instruction. This is deprecated because
2011    * callers should explicitly provide the next instruction (depending on the
2012    * skipped insn)
2013    */
2014   @Deprecated
2015   public void skipInstruction(){
2016     skipInstruction(getPC().getNext());
2017   }
2018
2019   public boolean isInstructionSkipped() {
2020     return (attributes & ATTR_SKIP_INSN_EXEC) != 0;
2021   }
2022
2023   public void skipInstructionLogging () {
2024     attributes |= ATTR_SKIP_INSN_LOG;
2025   }
2026
2027   /**
2028    * explicitly set the next insn to enter. To be used by listeners that
2029    * replace bytecode exec (during 'executeInstruction' notification
2030    *
2031    * Note this is dangerous because you have to make sure the operand stack is
2032    * in a consistent state. This also will fail if someone already ordered
2033    * reexecution of the current instruction
2034    */
2035   public boolean setNextPC (Instruction insn) {
2036     if (nextPc == null){
2037       // this is pre-execution, if we don't skip then the next insn.execute() is going
2038       // to override what we set here
2039       attributes |= ATTR_SKIP_INSN_EXEC;
2040       nextPc = insn;
2041       return true;
2042       
2043     } else {
2044       if (top != null && nextPc != top.getPC()){ // this needs to be re-executed
2045         nextPc = insn;   
2046         return true;
2047       }
2048     }
2049     
2050     return false;
2051   }
2052
2053   /**
2054    * Executes a method call. Be aware that it executes the whole method as one atomic
2055    * step. Arguments have to be already on the provided stack
2056    *
2057    * This only works for non-native methods, and does not allow any choice points,
2058    * so you have to know very well what you are doing.
2059    *
2060    * Instructions executed by this method are still fully observable and stored in
2061    * the path
2062    */
2063   public void executeMethodAtomic (StackFrame frame) {
2064
2065     pushFrame(frame);
2066     int    depth = countStackFrames();
2067     Instruction pc = frame.getPC();
2068     SystemState ss = vm.getSystemState();
2069
2070     ss.incAtomic(); // to shut off avoidable context switches (MONITOR_ENTER and wait() can still block)
2071
2072     while (depth <= countStackFrames()) {
2073       Instruction nextPC = executeInstruction();
2074
2075       if (ss.getNextChoiceGenerator() != null) {
2076         // BANG - we can't have CG's here
2077         // should be rather an ordinary exception
2078         // createAndThrowException("java.lang.AssertionError", "choice point in sync executed method: " + frame);
2079         throw new JPFException("choice point in atomic method execution: " + frame);
2080       } else {
2081         pc = nextPC;
2082       }
2083     }
2084
2085     vm.getSystemState().decAtomic();
2086
2087     nextPc = null;
2088
2089     // the frame was already removed by the RETURN insn of the frame's method
2090   }
2091
2092   /**
2093    * enter method atomically, but also hide it from listeners and do NOT add
2094    * executed instructions to the path.
2095    *
2096    * this can be even more confusing than executeMethodAtomic(), since
2097    * nothing prevents such a method from changing the program state, and we
2098    * wouldn't know for what reason by looking at the trace
2099    *
2100    * this method should only be used if we have to enter test application code
2101    * like hashCode() or equals() from native code, e.g. to silently check property
2102    * violations
2103    *
2104    * executeMethodHidden also acts as an exception firewall, since we don't want
2105    * any silently executed code fall back into the visible path (for
2106    * no observable reason)
2107    */
2108   public void executeMethodHidden (StackFrame frame) {
2109
2110     pushFrame(frame);
2111     
2112     int depth = countStackFrames(); // this includes the DirectCallStackFrame
2113     Instruction pc = frame.getPC();
2114
2115     vm.getSystemState().incAtomic(); // to shut off avoidable context switches (MONITOR_ENTER and wait() can still block)
2116
2117     while (depth <= countStackFrames()) {
2118       Instruction nextPC = executeInstructionHidden();
2119
2120       if (pendingException != null) {
2121
2122       } else {
2123         if (nextPC == pc) {
2124           // BANG - we can't have CG's here
2125           // should be rather an ordinary exception
2126           // createAndThrowException("java.lang.AssertionError", "choice point in sync executed method: " + frame);
2127           throw new JPFException("choice point in hidden method execution: " + frame);
2128         } else {
2129           pc = nextPC;
2130         }
2131       }
2132     }
2133
2134     vm.getSystemState().decAtomic();
2135
2136     nextPc = null;
2137
2138     // the frame was already removed by the RETURN insn of the frame's method
2139   }
2140
2141   public Heap getHeap () {
2142     return vm.getHeap();
2143   }
2144
2145   public ElementInfo getElementInfo (int objRef) {
2146     Heap heap = vm.getHeap();
2147     return heap.get(objRef);
2148   }
2149   
2150   public ElementInfo getModifiableElementInfo (int ref) {
2151     Heap heap = vm.getHeap();
2152     return heap.getModifiable(ref);
2153   }
2154   
2155   public ElementInfo getBlockedObject (MethodInfo mi, boolean isBeforeCall, boolean isModifiable) {
2156     int         objref;
2157     ElementInfo ei = null;
2158
2159     if (mi.isSynchronized()) {
2160       if (mi.isStatic()) {
2161         objref = mi.getClassInfo().getClassObjectRef();
2162       } else {
2163         // NOTE 'inMethod' doesn't work for natives, because getThis() pulls 'this' from the stack frame, 
2164         // which we don't have (and don't need) for natives
2165         objref = isBeforeCall ? getCalleeThis(mi) : getThis();
2166       }
2167
2168       ei = (isModifiable) ? getModifiableElementInfo(objref) : getElementInfo(objref);
2169
2170       assert (ei != null) : ("inconsistent stack, no object or class ref: " +
2171                                mi.getFullName() + " (" + objref +")");
2172     }
2173
2174     return ei;
2175   }
2176
2177   //--- convenience methods for call sites that don't have direct access to the VM
2178   
2179   public boolean setNextChoiceGenerator (ChoiceGenerator<?> cg){
2180     return vm.setNextChoiceGenerator(cg);
2181   }
2182   
2183   public boolean hasNextChoiceGenerator(){
2184     return vm.hasNextChoiceGenerator();
2185   }
2186
2187   public void checkNextChoiceGeneratorSet (String msg){
2188     if (!vm.hasNextChoiceGenerator()){
2189       throw new JPFException(msg);
2190     }
2191   }
2192   
2193   //--- call processing
2194   
2195   /**
2196    * note - this assumes the stackframe of the method to enter is already initialized and on top (pushed)
2197    */
2198   public void enter (){
2199     MethodInfo mi = top.getMethodInfo();
2200
2201     if (!mi.isJPFExecutable()){
2202       //printStackTrace();
2203       throw new JPFException("method is not JPF executable: " + mi);
2204     }
2205
2206     if (mi.isSynchronized()){
2207       int oref = mi.isStatic() ?  mi.getClassInfo().getClassObjectRef() : top.getThis();
2208       ElementInfo ei = getModifiableElementInfo( oref);
2209       
2210       ei.lock(this);
2211     }
2212
2213     vm.notifyMethodEntered(this, mi);
2214   }
2215
2216   /**
2217    * note - this assumes the stackframe is still on top (not yet popped)
2218    * 
2219    * return true if any threads became unblocked due to a return from a sync method
2220    */
2221   public boolean leave(){
2222     boolean didUnblock = false;
2223     MethodInfo mi = top.getMethodInfo();
2224     
2225     // <2do> - that's not really enough, we might have suspicious bytecode that fails
2226     // to release locks acquired by monitor_enter (e.g. by not having a handler that
2227     // monitor_exits & re-throws). That's probably shifted into the bytecode verifier
2228     // in the future (i.e. outside JPF), but maybe we should add an explicit test here
2229     // and report an error if the code does asymmetric locking (according to the specs,
2230     // VMs are allowed to silently fix this, so it might run on some and fail on others)
2231     
2232     if (mi.isSynchronized()) {
2233       int oref = mi.isStatic() ?  mi.getClassInfo().getClassObjectRef() : top.getThis();
2234       ElementInfo ei = getElementInfo( oref);
2235       if (ei.isLocked()){
2236         ei = ei.getModifiableInstance();
2237         didUnblock = ei.unlock(this);
2238       }
2239     }
2240
2241     vm.notifyMethodExited(this, mi);
2242     return didUnblock;
2243   }
2244
2245   
2246   /**
2247    * this should only be called from the top half of the last DIRECTCALLRETURN of
2248    * a thread.
2249    * @return true - if the thread is done, false - if instruction has to be re-executed
2250    */
2251   public boolean exit(){
2252     int objref = getThreadObjectRef();
2253     ElementInfo ei = getModifiableElementInfo(objref); // we are going to modify it no matter what
2254     SystemState ss = vm.getSystemState();
2255     Scheduler scheduler = getScheduler();
2256
2257     enableEmptyTransition();
2258     
2259     // if this is the last non-daemon and there are only daemons left (which
2260     // would be killed by our termination) we have to give them a chance to
2261     // run BEFORE we terminate, to catch errors in those daemons we might have
2262     // triggered in our last transition. Even if a daemon has a proper CG
2263     // on the trigger that would expose the error subsequently, it would not be
2264     // scheduled anymore but hard terminated. This is even true if the trigger
2265     // is the last operation in the daemon since a host VM might preempt
2266     // on every instruction, not just CG insns (see .test.mc.DaemonTest)
2267     if (vm.getThreadList().hasOnlyMatchingOtherThan(this, vm.getDaemonRunnablePredicate())) {
2268       if (scheduler.setsRescheduleCG(this, "daemonTermination")) {
2269         return false;
2270       }
2271     }
2272     
2273     // beware - this notifies all waiters for this thread (e.g. in a join())
2274     // hence it has to be able to acquire the lock
2275     if (!ei.canLock(this)) {
2276       // if we can't acquire the lock, it means there needs to be another live thread,
2277       // but it might not be runnable (deadlock) and we don't want to mask that error
2278       
2279       // block first, so that we don't get this thread in the list of CGs
2280       ei.block(this);
2281       if (!scheduler.setsBlockedThreadCG(this, ei)){
2282         throw new JPFException("blocking thread termination without transition break");            
2283       }    
2284       return false; // come back once we can obtain the lock to notify our waiters
2285     }
2286       
2287     // we have to be able to acquire the group lock since we are going to remove
2288     // the thread from the group
2289     int grpRef = getThreadGroupRef();
2290     ElementInfo eiGrp = getModifiableElementInfo(grpRef);
2291     if (eiGrp != null){
2292       if (!eiGrp.canLock(this)){
2293         eiGrp.block(this);
2294         if (!scheduler.setsBlockedThreadCG(this, eiGrp)){
2295           throw new JPFException("blocking thread termination on group without transition break");            
2296         }    
2297         return false; // come back once we can obtain the lock to update the group
2298       }
2299     }
2300
2301     // Ok, we can get the lock, time to die
2302     
2303     // this simulates the ThreadGroup.remove(), which would cause a lot
2304     // of states if done in bytecode. Since we don't have a ThreadGroup peer
2305     // we keep all this code in ThreadInfo.
2306     // This might cause the ThreadGroup to notify waiters, which has to
2307     // happen before the notification on the thread object
2308     eiGrp.lock(this);
2309     cleanupThreadGroup(grpRef, objref);
2310     eiGrp.unlock(this);
2311     
2312     
2313     // notify waiters on thread termination
2314     if (!holdsLock(ei)) {
2315       // we only need to increase the lockcount if we don't own the lock yet,
2316       // as is the case for synchronized run() in anonymous threads (otherwise
2317       // we have a lockcount > 1 and hence do not unlock upon return)
2318       ei.lock(this);
2319     }
2320
2321     ei.notifiesAll(); // watch out, this might change the runnable count
2322     ei.unlock(this);
2323
2324     setState(State.TERMINATED);
2325
2326     // we don't unregister this thread yet, this happens when the corresponding
2327     // thread object is collected
2328     ss.clearAtomic();
2329     cleanupThreadObject(ei);
2330     vm.activateGC();  // stack is gone, so reachability might change
2331
2332     // give the thread tracking policy a chance to remove this thread from
2333     // object/class thread sets
2334     scheduler.cleanupThreadTermination(this);
2335
2336     if (vm.getThreadList().hasAnyMatchingOtherThan(this, getRunnableNonDaemonPredicate())) {
2337       if (!scheduler.setsTerminationCG(this)){
2338         throw new JPFException("thread termination without transition break");
2339       }
2340     }
2341
2342     popFrame(); // we need to do this *after* setting the CG (so that we still have a CG insn)
2343
2344     return true;
2345   }
2346
2347   Predicate<ThreadInfo> getRunnableNonDaemonPredicate() {
2348     return new Predicate<ThreadInfo>() {
2349       @Override
2350         public boolean isTrue (ThreadInfo ti) {
2351         return (ti.isRunnable() && !ti.isDaemon());
2352       }
2353     };
2354   }
2355   
2356   /**
2357    * this is called upon ThreadInfo.exit() and corresponds to the private Thread.exit()
2358    */
2359   void cleanupThreadObject (ElementInfo ei) {
2360     // ideally, this should be done by calling Thread.exit(), but this
2361     // does a ThreadGroup.remove(), which does a lot of sync stuff on the shared
2362     // ThreadGroup object, which might create lots of states. So we just nullify
2363     // the Thread fields and remove it from the ThreadGroup from here
2364     int grpRef = ei.getReferenceField("group");
2365     cleanupThreadGroup(grpRef, ei.getObjectRef());
2366
2367     ei.setReferenceField("group", MJIEnv.NULL);    
2368     ei.setReferenceField("threadLocals", MJIEnv.NULL);
2369     
2370     ei.setReferenceField("uncaughtExceptionHandler", MJIEnv.NULL);
2371   }
2372
2373   /**
2374    * this is called upon ThreadInfo.exit() and corresponds to ThreadGroup.remove(t), which is called from Thread.exit()
2375    * 
2376    * ideally this should be in the ThreadGroup peer, but we don't want to reference concrete peers from core (which is the
2377    * lowest layer).
2378    * Since we already depend on ThreadGroup fields during VM initialization we just keep all Thread/ThreadGroup
2379    * related methods here
2380    */
2381   void cleanupThreadGroup (int grpRef, int threadRef) {
2382     if (grpRef != MJIEnv.NULL) {
2383       ElementInfo eiGrp = getModifiableElementInfo(grpRef);
2384       int threadsRef = eiGrp.getReferenceField("threads");
2385       if (threadsRef != MJIEnv.NULL) {
2386         ElementInfo eiThreads = getModifiableElementInfo(threadsRef);
2387         if (eiThreads.isArray()) {
2388           int nthreads = eiGrp.getIntField("nthreads");
2389
2390           for (int i=0; i<nthreads; i++) {
2391             int tref = eiThreads.getReferenceElement(i);
2392
2393             if (tref == threadRef) { // compact the threads array
2394               int n1 = nthreads-1;
2395               for (int j=i; j<n1; j++) {
2396                 eiThreads.setReferenceElement(j, eiThreads.getReferenceElement(j+1));
2397               }
2398               eiThreads.setReferenceElement(n1, MJIEnv.NULL);
2399
2400               eiGrp.setIntField("nthreads", n1);
2401               if (n1 == 0) {
2402                 eiGrp.lock(this);
2403                 eiGrp.notifiesAll();
2404                 eiGrp.unlock(this);
2405               }
2406
2407               // <2do> we should probably also check if we have to set it destroyed
2408               return;
2409             }
2410           }
2411         }
2412       }
2413     }
2414   }
2415
2416   /**
2417    * this is called by the VM upon initialization of the main thread. At this point, we have a tiMain and a java.lang.Thread
2418    * object, but there is no ThreadGroup yet
2419    * 
2420    * This method is here to keep all Thread/ThreadGroup field dependencies in one place. The downside of not keeping this in
2421    * VM is that we can't override in order to have specialized ThreadInfos, but there is no factory for them anyways
2422    */
2423   protected void createMainThreadObject (SystemClassLoaderInfo sysCl){
2424     //--- now create & initializeSharednessPolicy all the related JPF objects
2425     Heap heap = getHeap();
2426
2427     ClassInfo ciThread = sysCl.threadClassInfo;
2428     ElementInfo eiThread = heap.newObject( ciThread, this);
2429     objRef = eiThread.getObjectRef();
2430      
2431     ElementInfo eiName = heap.newString(MAIN_NAME, this);
2432     int nameRef = eiName.getObjectRef();
2433     eiThread.setReferenceField("name", nameRef);
2434     
2435     ElementInfo eiGroup = createMainThreadGroup(sysCl);
2436     eiThread.setReferenceField("group", eiGroup.getObjectRef());
2437     
2438     eiThread.setIntField("priority", Thread.NORM_PRIORITY);
2439
2440     ClassInfo ciPermit = sysCl.getResolvedClassInfo("java.lang.Thread$Permit");
2441     ElementInfo eiPermit = heap.newObject( ciPermit, this);
2442     eiPermit.setBooleanField("blockPark", true);
2443     eiThread.setReferenceField("permit", eiPermit.getObjectRef());
2444
2445     addToThreadGroup(eiGroup);
2446     
2447     addId( objRef, id);
2448
2449     //--- set the thread running
2450     setState(ThreadInfo.State.RUNNING);
2451   }
2452   
2453
2454   /**
2455    * this creates and inits the main ThreadGroup object, which we have to do explicitly since
2456    * we can't execute bytecode yet
2457    */
2458   protected ElementInfo createMainThreadGroup (SystemClassLoaderInfo sysCl) {
2459     Heap heap = getHeap();
2460     
2461     ClassInfo ciGroup = sysCl.getResolvedClassInfo("java.lang.ThreadGroup");
2462     ElementInfo eiThreadGrp = heap.newObject( ciGroup, this);
2463
2464     ElementInfo eiGrpName = heap.newString("main", this);
2465     eiThreadGrp.setReferenceField("name", eiGrpName.getObjectRef());
2466
2467     eiThreadGrp.setIntField("maxPriority", java.lang.Thread.MAX_PRIORITY);
2468
2469     // 'threads' and 'nthreads' will be set later from createMainThreadObject
2470
2471     return eiThreadGrp;
2472   }
2473
2474   /**
2475    * this is used for all thread objects, not just main 
2476    */
2477   protected void addToThreadGroup (ElementInfo eiGroup){
2478     FieldInfo finThreads = eiGroup.getFieldInfo("nthreads");
2479     int nThreads = eiGroup.getIntField(finThreads);
2480     
2481     if (eiGroup.getBooleanField("destroyed")){
2482       env.throwException("java.lang.IllegalThreadStateException");
2483       
2484     } else {
2485       FieldInfo fiThreads = eiGroup.getFieldInfo("threads");
2486       int threadsRef = eiGroup.getReferenceField(fiThreads);
2487       
2488       if (threadsRef == MJIEnv.NULL){
2489         threadsRef = env.newObjectArray("Ljava/lang/Thread;", 1);
2490         env.setReferenceArrayElement(threadsRef, 0, objRef);
2491         eiGroup.setReferenceField(fiThreads, threadsRef);
2492         
2493       } else {
2494         int newThreadsRef = env.newObjectArray("Ljava/lang/Thread;", nThreads+1);
2495         ElementInfo eiNewThreads = env.getElementInfo(newThreadsRef);        
2496         ElementInfo eiThreads = env.getElementInfo(threadsRef);
2497         
2498         for (int i=0; i<nThreads; i++){
2499           int tr = eiThreads.getReferenceElement(i);
2500           eiNewThreads.setReferenceElement(i, tr);
2501         }
2502         
2503         eiNewThreads.setReferenceElement(nThreads, objRef);
2504         eiGroup.setReferenceField(fiThreads, newThreadsRef);
2505       }
2506       
2507       eiGroup.setIntField(finThreads, nThreads+1);
2508       
2509       /** <2do> we don't model this yet
2510       FieldInfo finUnstartedThreads = eiGroup.getFieldInfo("nUnstartedThreads");
2511       int nUnstarted = eiGroup.getIntField(finUnstartedThreads);
2512       eiGroup.setIntField(finUnstartedThreads, nUnstarted-1);
2513       **/
2514     }    
2515   }
2516   
2517   
2518   public void hash (HashData hd) {
2519     threadData.hash(hd);
2520
2521     for (StackFrame f = top; f != null; f = f.getPrevious()){
2522       f.hash(hd);
2523     }
2524   }
2525
2526   public void interrupt () {
2527     ElementInfo eiThread = getModifiableElementInfo(getThreadObjectRef());
2528
2529     State status = getState();
2530
2531     switch (status) {
2532     case RUNNING:
2533     case BLOCKED:
2534     case UNBLOCKED:
2535     case NOTIFIED:
2536     case TIMEDOUT:
2537       // just set interrupt flag
2538       eiThread.setBooleanField("interrupted", true);
2539       break;
2540
2541     case WAITING:
2542     case TIMEOUT_WAITING:
2543       eiThread.setBooleanField("interrupted", true);
2544       setState(State.INTERRUPTED);
2545
2546       // since this is potentially called w/o owning the wait lock, we
2547       // have to check if the waiter goes directly to UNBLOCKED
2548       ElementInfo eiLock = getElementInfo(lockRef);
2549       if (eiLock.canLock(this)) {
2550         resetLockRef();
2551         setState(State.UNBLOCKED);
2552         
2553         // we cannot yet remove this thread from the Monitor lock contender list
2554         // since it still has to re-acquire the lock before becoming runnable again
2555         
2556         // NOTE: this can lead to attempts to reenter the same thread to the 
2557         // lock contender list if the interrupt handler of the interrupted thread
2558         // tries to wait/block/park again
2559         //eiLock.setMonitorWithoutLocked(this);
2560       }
2561       
2562       break;
2563
2564     case NEW:
2565     case TERMINATED:
2566       // ignore
2567       break;
2568
2569     default:
2570     }
2571   }
2572
2573   /**
2574    * mark all objects during gc phase1 which are reachable from this threads
2575    * root set (Thread object, Runnable, stack)
2576    * @aspects: gc
2577    */
2578   void markRoots (Heap heap) {
2579     
2580     // 1. mark the Thread object itself
2581     heap.markThreadRoot(objRef, id);
2582
2583     // 2. and its runnable
2584     if (targetRef != MJIEnv.NULL) {
2585       heap.markThreadRoot(targetRef,id);
2586     }
2587
2588     // 3. if we have a pending exception that wasn't handled, make sure the exception object is not collected before we match states
2589     if (pendingException != null){
2590       heap.markThreadRoot(pendingException.getExceptionReference(), id);
2591     }
2592     
2593     // 4. now all references on the stack
2594     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
2595       frame.markThreadRoots(heap, id);
2596     }
2597   }
2598
2599
2600   /**
2601    * replace the top frame - this is a dangerous method that should only
2602    * be used from Restoreres and to restore operators and locals in post-execution notifications
2603    * to their pre-execution contents
2604    */
2605   public void setTopFrame (StackFrame frame) {
2606     top = frame;
2607
2608     // since we have swapped the top frame, the stackDepth might have changed
2609     int n = 0;
2610     for (StackFrame f = frame; f != null; f = f.getPrevious()){
2611       n++;
2612     }
2613     stackDepth = n;
2614   }
2615
2616   /**
2617    * Adds a new stack frame for a new called method.
2618    */
2619   public void pushFrame (StackFrame frame) {
2620
2621     frame.setPrevious(top);
2622
2623     top = frame;
2624     stackDepth++;
2625
2626     // a new frame cannot have been stored yet, so we don't need to clone on the next mod
2627     // note this depends on not pushing a frame in the top half of a CG method
2628     markTfChanged(top);
2629
2630     returnedDirectCall = null;
2631   }
2632
2633   /**
2634    * Removes a stack frame
2635    */
2636   public void popFrame() {
2637     StackFrame frame = top;
2638
2639     //--- do our housekeeping
2640     if (frame.hasAnyRef()) {
2641       vm.getSystemState().activateGC();
2642     }
2643
2644     // there always is one since we start all threads through directcalls
2645     top = frame.getPrevious();
2646     stackDepth--;
2647   }
2648
2649   public StackFrame popAndGetModifiableTopFrame() {
2650     popFrame();
2651
2652     if (top.isFrozen()) {
2653       top = top.clone();
2654     }
2655     
2656     return top;
2657   }
2658   
2659   public StackFrame popAndGetTopFrame(){
2660     popFrame();
2661     return top;
2662   }
2663   
2664   /**
2665    * removing DirectCallStackFrames is a bit different (only happens from
2666    * DIRECTCALLRETURN insns)
2667    */
2668   public StackFrame popDirectCallFrame() {
2669     //assert top instanceof DirectCallStackFrame;
2670
2671     returnedDirectCall = (DirectCallStackFrame) top;
2672
2673     if (top.hasFrameAttr( UncaughtHandlerAttr.class)){
2674       return popUncaughtHandlerFrame();
2675     }
2676     
2677     top = top.getPrevious();
2678     stackDepth--;
2679     
2680     return top;
2681   }
2682
2683   
2684   public boolean hasReturnedFromDirectCall () {
2685     // this is reset each time we push a new frame
2686     return (returnedDirectCall != null);
2687   }
2688
2689   public boolean hasReturnedFromDirectCall(String directCallId){
2690     return (returnedDirectCall != null &&
2691             returnedDirectCall.getMethodName().equals(directCallId));
2692   }
2693
2694   public DirectCallStackFrame getReturnedDirectCall () {
2695     return returnedDirectCall;
2696   }
2697
2698
2699   public String getStateDescription () {
2700     StringBuilder sb = new StringBuilder("thread ");
2701     sb.append(getThreadObjectClassInfo().getName());
2702     sb.append(":{id:");
2703     sb.append(id);
2704     sb.append(',');
2705     sb.append(threadData.getFieldValues());
2706     sb.append('}');
2707     
2708     return sb.toString();
2709   }
2710
2711   public ClassInfo getThreadObjectClassInfo() {
2712     return getThreadObject().getClassInfo();
2713   }
2714   
2715   /**
2716    * Prints the content of the stack
2717    */
2718   public void printStackContent () {
2719     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
2720       frame.printStackContent();
2721     }
2722   }
2723
2724   /**
2725    * Prints current stacktrace information
2726    */
2727   public void printStackTrace () {
2728     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()){
2729       frame.printStackTrace();
2730     }
2731   }
2732
2733   protected boolean haltOnThrow (String exceptionClassName){
2734     if ((haltOnThrow != null) && (haltOnThrow.matchesAny(exceptionClassName))){
2735       return true;
2736     }
2737
2738     return false;
2739   }
2740
2741   protected Instruction throwStopException (){
2742     // <2do> maybe we should do a little sanity check first
2743     ElementInfo ei = getModifiableThreadObject();
2744
2745     int xRef = ei.getReferenceField("stopException");
2746     ei.setReferenceField("stopException", MJIEnv.NULL);
2747     attributes &= ~ATTR_SET_STOPPED;  // otherwise we would throw again if thread gets still executed
2748
2749     Instruction insn = getPC();
2750     if (insn instanceof EXECUTENATIVE){
2751       // we only get here if there was a CG in a native method and we might
2752       // have to reacquire a lock to go on
2753
2754       // <2do> it would be better if we could avoid to enter the native method
2755       // since it might have side effects like overwriting the exception or
2756       // doing roundtrips in its bottom half, but we don't know which lock that
2757       // is (lockRef might be already reset)
2758
2759       env.throwException(xRef);
2760       return insn;
2761     }
2762
2763     return throwException(xRef);
2764   }
2765   
2766   /**
2767    * this is basically a side-effect free version of throwException to determine if a given
2768    * exception will be handled.
2769    */
2770   public HandlerContext getHandlerContextFor (ClassInfo ciException){
2771     ExceptionHandler matchingHandler = null; // the matching handler we found (if any)
2772     
2773     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()) {
2774       // that means we have to turn the exception into an InvocationTargetException
2775       if (frame.isReflection()) {
2776         ciException = ClassInfo.getInitializedSystemClassInfo("java.lang.reflect.InvocationTargetException", this);
2777       }
2778
2779       matchingHandler = frame.getHandlerFor( ciException);
2780       if (matchingHandler != null){
2781         return new HandlerContext( this, ciException, frame, matchingHandler);
2782       }
2783     }
2784     
2785     if (!ignoreUncaughtHandlers && !isUncaughtHandlerOnStack()) {
2786       int uchRef;
2787       if ((uchRef = getInstanceUncaughtHandler()) != MJIEnv.NULL) {
2788         return new HandlerContext( this, ciException, HandlerContext.UncaughtHandlerType.INSTANCE, uchRef);
2789       }
2790
2791       int grpRef = getThreadGroupRef();
2792       if ((uchRef = getThreadGroupUncaughtHandler(grpRef)) != MJIEnv.NULL) {
2793         return new HandlerContext( this, ciException, HandlerContext.UncaughtHandlerType.GROUP, uchRef);
2794       }
2795
2796       if ((uchRef = getGlobalUncaughtHandler()) != MJIEnv.NULL) {
2797         return new HandlerContext( this, ciException, HandlerContext.UncaughtHandlerType.GLOBAL, uchRef);
2798       }
2799     }
2800     
2801     return null;
2802   }
2803   
2804   /**
2805    * unwind stack frames until we find a matching handler for the exception object
2806    */
2807   public Instruction throwException (int exceptionObjRef) {
2808     Heap heap = vm.getHeap();
2809     ElementInfo eiException = heap.get(exceptionObjRef);
2810     ClassInfo ciException = eiException.getClassInfo();
2811     String exceptionName = ciException.getName();
2812     StackFrame handlerFrame = null; // the stackframe that has a matching handler (if any)
2813     ExceptionHandler matchingHandler = null; // the matching handler we found (if any)
2814
2815     // first, give the VM a chance to intercept (we do this before changing anything)
2816     Instruction insn = vm.handleException(this, exceptionObjRef);
2817     if (insn != null){
2818       return insn;
2819     }
2820
2821     // we don't have to store the stacktrace explicitly anymore, since that is now
2822     // done in the Throwable ctor (more specifically the native fillInStackTrace)
2823     pendingException = new ExceptionInfo(this, eiException);
2824
2825     vm.notifyExceptionThrown(this, eiException);
2826
2827     if (haltOnThrow(exceptionName)) {
2828       // shortcut - we don't try to find a handler for this one but bail immediately
2829       //NoUncaughtExceptionsProperty.setExceptionInfo(pendingException);
2830       throw new UncaughtException(this, exceptionObjRef);
2831     }
2832
2833     // check if we find a matching handler, and if we do store it. Leave the
2834     // stack untouched so that listeners can still inspect it
2835     for (StackFrame frame = top; (frame != null) && (handlerFrame == null); frame = frame.getPrevious()) {
2836       // that means we have to turn the exception into an InvocationTargetException
2837       if (frame.isReflection()) {
2838         // make sure it's in the startup class set since we are not able to re-execute here
2839         ciException = ClassInfo.getInitializedSystemClassInfo("java.lang.reflect.InvocationTargetException", this);
2840         exceptionObjRef  = createException(ciException, exceptionName, exceptionObjRef);
2841         exceptionName = ciException.getName();
2842         eiException = heap.get(exceptionObjRef);
2843         pendingException = new ExceptionInfo(this, eiException);
2844       }
2845
2846       matchingHandler = frame.getHandlerFor( ciException);
2847       if (matchingHandler != null){
2848         handlerFrame = frame;
2849         break;
2850       }
2851
2852       if ((handlerFrame == null) && frame.isFirewall()) {
2853         // this method should not let exceptionHandlers pass into lower level stack frames
2854         // (e.g. for <clinit>, or hidden direct calls)
2855         // <2do> if this is a <clinit>, we should probably turn into an
2856         // ExceptionInInitializerError first
2857         unwindTo(frame);
2858         //NoUncaughtExceptionsProperty.setExceptionInfo(pendingException);
2859         throw new UncaughtException(this, exceptionObjRef);
2860       }
2861     }
2862
2863     if (handlerFrame == null) {
2864       // we still have to check if there is a Thread.UncaughtExceptionHandler in effect,
2865       // and if we already enter within one, in which case we don't reenter it
2866       if (!ignoreUncaughtHandlers && !isUncaughtHandlerOnStack()) {
2867         // we use a direct call instead of exception handlers within the run()/main()
2868         // direct call methods because we want to preserve the whole stack in case
2869         // we treat returned (report-only) handlers as NoUncaughtExceptionProperty
2870         // violations (passUncaughtHandler=false)
2871         insn = callUncaughtHandler(pendingException);
2872         if (insn != null) {
2873           // we only do this if there is a UncaughtHandler other than the standard
2874           // ThreadGroup, hence we have to check for the return value. If there is
2875           // only ThreadGroup.uncaughtException(), we put the system out of its misery
2876           return insn;
2877         }
2878       }
2879
2880       // there was no overridden uncaughtHandler, or we already executed it
2881       if ("java.lang.ThreadDeath".equals(exceptionName)) { // gracefully shut down
2882         unwindToFirstFrame();
2883         pendingException = null;
2884         return top.getPC().getNext(); // the final DIRECTCALLRETURN
2885
2886       } else { // we have a NoUncaughtPropertyViolation
2887         //NoUncaughtExceptionsProperty.setExceptionInfo(pendingException);
2888         throw new UncaughtException(this, exceptionObjRef);
2889       }
2890
2891     } else { // we found a matching handler
2892       
2893       unwindTo(handlerFrame);
2894
2895       // according to the VM spec, before transferring control to the handler we have
2896       // to reset the operand stack to contain only the exception reference
2897       // (4.9.2 - "4. merge the state of the operand stack..")
2898       handlerFrame = getModifiableTopFrame();
2899       handlerFrame.setExceptionReference(exceptionObjRef);
2900
2901       // jump to the exception handler and set pc so that listeners can see it
2902       int handlerOffset = matchingHandler.getHandler();
2903       insn = handlerFrame.getMethodInfo().getInstructionAt(handlerOffset);
2904       handlerFrame.setPC(insn);
2905
2906       // notify before we reset the pendingException
2907       vm.notifyExceptionHandled(this);
2908
2909       pendingException = null; // handled, no need to keep it
2910
2911       return insn;
2912     }
2913   }
2914
2915   /**
2916    * is there any UncaughHandler in effect for this thread?
2917    * NOTE - this doesn't check if we are already executing one (i.e. it would still handle an exception)
2918    * or if uncaughtHandlers are enabled within JPF
2919    */
2920   public boolean hasUncaughtHandler (){
2921     if (getInstanceUncaughtHandler() != MJIEnv.NULL){
2922       return true;
2923     }
2924     
2925     int grpRef = getThreadGroupRef();
2926     if (getThreadGroupUncaughtHandler(grpRef) != MJIEnv.NULL){
2927       return true;
2928     }
2929     
2930     if (getGlobalUncaughtHandler() != MJIEnv.NULL){
2931       return true;
2932     }
2933     
2934     return false;
2935   }
2936   
2937   /**
2938    * this explicitly models the standard ThreadGroup.uncaughtException(), but we want
2939    * to save us a roundtrip if that's the only handler we got. If we would use
2940    * a handler block in the run()/main() direct call stubs that just delegate to
2941    * the standard ThreadGroup.uncaughtException(), we would have trouble mapping
2942    * this to NoUncaughtExceptionProperty violations (which is just a normal
2943    * printStackTrace() in there).
2944    */
2945   protected Instruction callUncaughtHandler (ExceptionInfo xi){
2946     Instruction insn = null;
2947     
2948     // 1. check if this thread has its own uncaughtExceptionHandler set. If not,
2949     // hand it over to ThreadGroup.uncaughtException()
2950     int  hRef = getInstanceUncaughtHandler();
2951     if (hRef != MJIEnv.NULL){
2952       insn = callUncaughtHandler(xi, hRef, "[threadUncaughtHandler]");
2953       
2954     } else {
2955       // 2. check if any of the ThreadGroup chain has an overridden uncaughtException
2956       int grpRef = getThreadGroupRef();
2957       hRef = getThreadGroupUncaughtHandler(grpRef);
2958       
2959       if (hRef != MJIEnv.NULL){
2960         insn = callUncaughtHandler(xi, hRef, "[threadGroupUncaughtHandler]");
2961       
2962       } else {
2963         // 3. as a last measure, check if there is a global handler 
2964         hRef = getGlobalUncaughtHandler();
2965         if (hRef != MJIEnv.NULL){
2966           insn = callUncaughtHandler(xi, hRef, "[globalUncaughtHandler]");
2967         }    
2968       }
2969     }
2970     
2971     return insn;
2972   }
2973   
2974   protected boolean isUncaughtHandlerOnStack(){
2975     for (StackFrame frame = top; frame != null; frame = frame.getPrevious()) {
2976       if (frame.hasFrameAttr(UncaughtHandlerAttr.class)){
2977         return true;
2978       }
2979     }
2980     
2981     return false;
2982   }
2983   
2984   protected int getInstanceUncaughtHandler (){
2985     ElementInfo ei = getElementInfo(objRef);
2986     int handlerRef = ei.getReferenceField("uncaughtExceptionHandler");
2987     return handlerRef;
2988   }
2989   
2990   protected int getThreadGroupRef() {
2991     ElementInfo ei = getElementInfo(objRef);
2992     int groupRef = ei.getReferenceField("group");
2993     return groupRef;
2994   }
2995   
2996   protected int getThreadGroupUncaughtHandler (int grpRef){
2997
2998     // get the first overridden uncaughtException() implementation in the group chain
2999     while (grpRef != MJIEnv.NULL){
3000       ElementInfo eiGrp = getElementInfo(grpRef);
3001       ClassInfo ciGrp = eiGrp.getClassInfo();
3002       MethodInfo miHandler = ciGrp.getMethod("uncaughtException(Ljava/lang/Thread;Ljava/lang/Throwable;)V", true);
3003       ClassInfo ciHandler = miHandler.getClassInfo();
3004       if (!ciHandler.getName().equals("java.lang.ThreadGroup")) {
3005         return eiGrp.getObjectRef();
3006       }
3007
3008       grpRef = eiGrp.getReferenceField("parent");
3009     }
3010     
3011     // no overridden uncaughtHandler found
3012     return MJIEnv.NULL;
3013   }
3014   
3015   protected int getGlobalUncaughtHandler(){
3016     ElementInfo ei = getElementInfo(objRef);
3017     ClassInfo ci = ei.getClassInfo();
3018     FieldInfo fi = ci.getStaticField("defaultUncaughtExceptionHandler");
3019     
3020     // the field is in our java.lang.Thread, but the concrete thread object class might differ
3021     ClassInfo fci = fi.getClassInfo();
3022     return fci.getStaticElementInfo().getReferenceField(fi);
3023   }
3024   
3025   /**
3026    * using an attribute to mark DirectCallStackFrames executing uncaughtHandlers is not
3027    * ideal, but the case is so exotic that we don't want another concrete StackFrame subclass that
3028    * would have to be created through the ClassInfo factory. Apart from retrieving the 
3029    * ExceptionInfo this is just a normal DirectCallStackFrame.
3030    * We could directly use ExceptionInfo, but it seems more advisable to have a dedicated,
3031    * private type. This could also store execution state
3032    */
3033   class UncaughtHandlerAttr implements SystemAttribute {
3034     ExceptionInfo xInfo;
3035     
3036     UncaughtHandlerAttr (ExceptionInfo xInfo){
3037       this.xInfo = xInfo;
3038     }
3039     
3040     ExceptionInfo getExceptionInfo(){
3041       return xInfo;
3042     }
3043   }
3044   
3045   protected Instruction callUncaughtHandler (ExceptionInfo xi, int handlerRef, String id){
3046     ElementInfo eiHandler = getElementInfo(handlerRef);
3047     ClassInfo ciHandler = eiHandler.getClassInfo();
3048     MethodInfo miHandler = ciHandler.getMethod("uncaughtException(Ljava/lang/Thread;Ljava/lang/Throwable;)V", true);
3049
3050     // we have to clear this here in case there is a CG while executing the uncaughtHandler
3051     pendingException = null;
3052     
3053     DirectCallStackFrame frame = miHandler.createDirectCallStackFrame(this, 0);
3054     int argOffset = frame.setReferenceArgument( 0, handlerRef, null);
3055     argOffset = frame.setReferenceArgument( argOffset, objRef, null);
3056     frame.setReferenceArgument( argOffset, xi.getExceptionReference(), null);
3057     
3058     UncaughtHandlerAttr uchContext = new UncaughtHandlerAttr( xi);
3059     frame.setFrameAttr( uchContext);
3060     
3061     pushFrame(frame);
3062     return frame.getPC();
3063   }
3064   
3065   protected StackFrame popUncaughtHandlerFrame(){    
3066     // we return from an overridden uncaughtException() direct call, but
3067     // its debatable if this counts as 'handled'. For handlers that just do
3068     // reporting this is probably false and we want JPF to report the defect.
3069     // If this is a fail-safe handler that tries to clean up so that other threads can
3070     // take over, we want to be able to go on and properly shut down the 
3071     // thread without property violation
3072     
3073     if (passUncaughtHandler) {
3074       // gracefully shutdown this thread
3075       unwindToFirstFrame(); // this will take care of notifying
3076       
3077       getModifiableTopFrame().advancePC();
3078       assert top.getPC() instanceof ReturnInstruction : "topframe PC not a ReturnInstruction: " + top.getPC();
3079       return top;
3080
3081     } else {
3082       // treat this still as an NoUncaughtExceptionProperty violation
3083       UncaughtHandlerAttr ctx = returnedDirectCall.getFrameAttr(UncaughtHandlerAttr.class);
3084       pendingException = ctx.getExceptionInfo();
3085       //NoUncaughtExceptionsProperty.setExceptionInfo(pendingException);
3086       throw new UncaughtException(this, pendingException.getExceptionReference());
3087     }
3088   }
3089
3090   
3091   protected void unwindTo (StackFrame newTopFrame){
3092     for (StackFrame frame = top; (frame != null) && (frame != newTopFrame); frame = frame.getPrevious()) {
3093       leave(); // that takes care of releasing locks
3094       vm.notifyExceptionBailout(this); // notify before we pop the frame
3095       popFrame();
3096     }
3097   }
3098
3099   protected StackFrame unwindToFirstFrame(){
3100     StackFrame frame;
3101
3102     for (frame = top; frame.getPrevious() != null; frame = frame.getPrevious()) {
3103       leave(); // that takes care of releasing locks
3104       vm.notifyExceptionBailout(this); // notify before we pop the frame
3105       popFrame();
3106     }
3107
3108     return frame;
3109   }
3110
3111   public ExceptionInfo getPendingException () {
3112     return pendingException;
3113   }
3114
3115   /**
3116    * watch out - just clearing it might cause an infinite loop
3117    * if we don't drop frames and/or advance the pc
3118    */
3119   public void clearPendingException () {
3120     //NoUncaughtExceptionsProperty.setExceptionInfo(null);
3121     pendingException = null;
3122   }
3123
3124   /**
3125    * Returns a clone of the thread data. To be called every time we change some ThreadData field
3126    * (which unfortunately includes lock counts, hence this should be changed)
3127    */
3128   protected ThreadData threadDataClone () {
3129     if ((attributes & ATTR_DATA_CHANGED) != 0) {
3130       // already cloned, so we don't have to clone
3131     } else {
3132       // reset, so that next storage request would recompute tdIndex
3133       markTdChanged();
3134       vm.kernelStateChanged();
3135
3136       threadData = threadData.clone();
3137     }
3138
3139     return threadData;
3140   }
3141
3142   public void restoreThreadData(ThreadData td) {
3143     threadData = td;
3144   }
3145
3146
3147   /**
3148    * this is a generic request to reschedule that is not based on instruction type
3149    * Note that we check for a mandatory CG, i.e. the policy has to return a CG to make sure
3150    * there is a transition break. We still go through the policy object for selection
3151    * of scheduling choices though
3152    * 
3153    */
3154   public boolean reschedule (String reason){
3155     return getScheduler().setsRescheduleCG(this, reason);
3156   }
3157   
3158   /**
3159    * this is a version that unconditionally breaks the current transition
3160    * without really adding choices. It only goes on with the same thread
3161    * (to avoid state explosion). Since we require a break, and there is no
3162    * choice (current thread is supposed to continue), there is no point 
3163    * going through the SyncPolicy
3164    *
3165    * if the current transition is already marked as ignored, this method does nothing
3166    */
3167   public boolean breakTransition(String reason) {
3168     SystemState ss = vm.getSystemState();
3169
3170     // no need to set a CG if this transition is already marked as ignored
3171     // (which will also break executeTransition)
3172     BreakGenerator cg = new BreakGenerator(reason, this, false);
3173     return ss.setNextChoiceGenerator(cg); // this breaks the transition
3174   }
3175   
3176   /**
3177    * this breaks the current transition with a CG that forces an end state (i.e.
3178    * has no choices)
3179    * this only takes effect if the current transition is not already marked
3180    * as ignored
3181    */
3182   public boolean breakTransition(boolean isTerminator) {
3183     SystemState ss = vm.getSystemState();
3184
3185     if (!ss.isIgnored()){
3186       BreakGenerator cg = new BreakGenerator( "breakTransition", this, isTerminator);
3187       return ss.setNextChoiceGenerator(cg); // this breaks the transition
3188     }
3189     
3190     return false;
3191   }
3192
3193   public boolean hasOtherRunnables () {
3194     return vm.getThreadList().hasAnyMatchingOtherThan(this, vm.getRunnablePredicate());
3195   }
3196   
3197   protected void markUnchanged() {
3198     attributes &= ~ATTR_ANY_CHANGED;
3199   }
3200
3201   protected void markTfChanged(StackFrame frame) {
3202     attributes |= ATTR_STACK_CHANGED;
3203     vm.kernelStateChanged();
3204   }
3205
3206   protected void markTdChanged() {
3207     attributes |= ATTR_DATA_CHANGED;
3208     vm.kernelStateChanged();
3209   }
3210
3211   public StackFrame getCallerStackFrame() {
3212     if (top != null){
3213       return top.getPrevious();
3214     } else {
3215       return null;
3216     }
3217   }
3218
3219   public int mixinExecutionStateHash(int h) {
3220     for (StackFrame frame = top; frame != null; frame = frame.prev) {
3221       if (!frame.isNative()) {
3222         h = frame.mixinExecutionStateHash(h);
3223       }
3224     }
3225     
3226     return h;
3227   }
3228   
3229   public boolean hasDataChanged() {
3230     return (attributes & ATTR_DATA_CHANGED) != 0;
3231   }
3232
3233   public boolean hasStackChanged() {
3234     return (attributes & ATTR_STACK_CHANGED) != 0;
3235   }
3236
3237   public boolean hasChanged() {
3238     return (attributes & ATTR_ANY_CHANGED) != 0;
3239   }
3240
3241   /**
3242    * Returns a clone of the top stack frame.
3243    */
3244   public StackFrame getModifiableTopFrame () {
3245     if (top.isFrozen()) {
3246       top = top.clone();
3247       markTfChanged(top);
3248     }
3249     return top;
3250   }
3251
3252   /**
3253    * Returns the top stack frame.
3254    */
3255   public StackFrame getTopFrame () {
3256     return top;
3257   }
3258
3259   /**
3260    * this replaces all frames up from 'frame' to 'top' with modifiable ones.
3261    * 
3262    * NOTE - you can't use this AFTER getModifiableTopFrame() since it changes top. Because
3263    * it is inherently unsafe, it should be used with care and you have to make sure nothing
3264    * else has stored top references, or respective references are updated after this call.
3265    * 
3266    * NOTE also that we assume there is no frozen frame on top of an unfrozen one
3267    * <2do> that should probably be reported as an error since it is a stack consistency violation
3268    */
3269   public StackFrame getModifiableFrame (StackFrame frame){
3270     StackFrame newTop = null;
3271     StackFrame last = null;
3272     boolean done = false;
3273     
3274     for (StackFrame f = top; f != null; f = f.getPrevious()){
3275       done = (f == frame);
3276       
3277       if (f.isFrozen()){
3278         f = f.clone();
3279         if (newTop == null){
3280           newTop = f;
3281         } else {
3282           last.setPrevious(f);
3283         }
3284         last = f;
3285         
3286       }
3287       
3288       if (done){ // done
3289         if (newTop != null){
3290           top = newTop;
3291           markTfChanged(top);
3292         }
3293         return f;
3294       }
3295     }
3296     
3297     return null; // it wasn't on the callstack
3298   }
3299   
3300   /**
3301    * note that we don't provide a modifiable version of this. All modifications
3302    * should only happen in the executing (top) frame
3303    */
3304   public StackFrame getStackFrameExecuting (Instruction insn, int offset){
3305     int n = offset;
3306     StackFrame frame = top;
3307
3308     for (; (n > 0) && frame != null; frame = frame.getPrevious()){
3309       n--;
3310     }
3311
3312     for(; frame != null; frame = frame.getPrevious()){
3313       if (frame.getPC() == insn){
3314         return frame;
3315       }
3316     }
3317
3318     return null;
3319   }
3320
3321   @Override
3322   public String toString() {
3323     return "ThreadInfo [name=" + getName() +
3324             ",id=" + id +
3325             ",state=" + getStateName() +
3326             // ",obj=" + Integer.toHexString(getThreadObjectRef()) +
3327             ']';
3328   }
3329
3330   void setDaemon (boolean isDaemon) {
3331     threadDataClone().isDaemon = isDaemon;
3332   }
3333
3334   public boolean isDaemon () {
3335     return threadData.isDaemon;
3336   }
3337
3338   public MJIEnv getMJIEnv () {
3339     return env;
3340   }
3341   
3342   void setName (String newName) {
3343     threadDataClone().name = newName;
3344
3345     // see 'setPriority()', only that it's more serious here, because the
3346     // java.lang.Thread name is stored as a char[]
3347   }
3348
3349   public void setPriority (int newPrio) {
3350     if (threadData.priority != newPrio) {
3351       threadDataClone().priority = newPrio;
3352
3353       // note that we don't update the java.lang.Thread object, but
3354       // use our threadData value (which works because the object
3355       // values are just used directly from the Thread ctors (from where we pull
3356       // it out in our ThreadInfo ctor), and henceforth only via our intercepted
3357       // native getters
3358     }
3359   }
3360
3361   public int getPriority () {
3362     return threadData.priority;
3363   }
3364
3365   /**
3366    * Comparison for sorting based on index.
3367    */
3368   @Override
3369   public int compareTo (ThreadInfo that) {
3370     return this.id - that.id;
3371   }
3372   
3373   
3374   /**
3375    * only for debugging purposes
3376    */
3377   public void checkConsistency(boolean isStore){
3378     checkAssertion(threadData != null, "no thread data");
3379     
3380     // if the thread is runnable, it can't be blocked
3381     if (isRunnable()){
3382       checkAssertion(lockRef == MJIEnv.NULL, "runnable thread with non-null lockRef: " + lockRef) ;
3383     }
3384     
3385     // every thread that has been started and is not terminated has to have a stackframe with a next pc
3386     if (!isTerminated() && !isNew()){
3387       checkAssertion( stackDepth > 0, "empty stack " + getState());
3388       checkAssertion( top != null, "no top frame");
3389       checkAssertion( top.getPC() != null, "no top PC");
3390     }
3391     
3392     // if we are timedout, the top pc has to be either on a native Object.wait() or Unsafe.park()
3393     if (isTimedOut()){
3394       Instruction insn = top.getPC();
3395       checkAssertion( insn instanceof EXECUTENATIVE, "thread timedout outside of native method");
3396       
3397       // this is a bit dangerous in case we introduce new timeout points
3398       MethodInfo mi = ((EXECUTENATIVE)insn).getExecutedMethod();
3399       String mname = mi.getUniqueName();
3400       checkAssertion( mname.equals("wait(J") || mname.equals("park(ZJ"), "timedout thread outside timeout method: " + mi.getFullName());
3401     }
3402   
3403     List<ElementInfo> lockedObjects = getLockedObjects();
3404     
3405     if (lockRef != MJIEnv.NULL){
3406       // object we are blocked on has to exist
3407       ElementInfo ei = this.getElementInfo(lockRef);
3408       checkAssertion( ei != null, "thread locked on non-existing object: " + lockRef);
3409       
3410       // we have to be in the lockedThreads list of that objects monitor
3411       checkAssertion( ei.isLocking(this), "thread blocked on non-locking object: " + ei);
3412         
3413       // can't be blocked on a lock we own (but could be in waiting before giving it up)
3414       if (!isWaiting() && lockedObjectReferences.length > 0){
3415         for (ElementInfo lei : lockedObjects){
3416             checkAssertion( lei.getObjectRef() != lockRef, "non-waiting thread blocked on owned lock: " + lei);
3417         }
3418       }
3419       
3420       // the state has to be BLOCKED, NOTIFIED, WAITING or TIMEOUT_WAITING
3421       checkAssertion( isWaiting() || isBlockedOrNotified(), "locked thread not waiting, blocked or notified");
3422       
3423     } else { // no lockRef set
3424       checkAssertion( !isWaiting() && !isBlockedOrNotified(), "non-locked thread is waiting, blocked or notified");
3425     }
3426     
3427     // if we have locked objects, we have to be the locking thread of each of them
3428     if (lockedObjects != null && !lockedObjects.isEmpty()){
3429       for (ElementInfo ei : lockedObjects){
3430         ThreadInfo lti = ei.getLockingThread();
3431         if (lti != null){
3432           checkAssertion(lti == this, "not the locking thread for locked object: " + ei + " owned by " + lti);
3433         } else {
3434           // can happen for a nested monitor lockout
3435         }
3436       }
3437     }
3438
3439   }
3440   
3441   protected void checkAssertion(boolean cond, String failMsg){
3442     if (!cond){
3443       System.out.println("!!!!!! failed thread consistency: "  + this + ": " + failMsg);
3444       vm.dumpThreadStates();
3445       assert false;
3446     }
3447   }
3448   
3449   public boolean isSystemThread() {
3450     return false;
3451   }
3452 }