001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.scheduler;
014    
015    import java.security.AccessController;
016    import java.security.PrivilegedAction;
017    
018    import org.jikesrvm.ArchitectureSpecific.CodeArray;
019    import org.jikesrvm.ArchitectureSpecific.Registers;
020    import org.jikesrvm.ArchitectureSpecificOpt.PostThreadSwitch;
021    import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACK_SIZE_NORMAL;
022    import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.INVISIBLE_METHOD_ID;
023    import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP;
024    import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACK_SIZE_GUARD;
025    import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_METHOD_ID_OFFSET;
026    import static org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_RETURN_ADDRESS_OFFSET;
027    import org.jikesrvm.ArchitectureSpecific.BaselineConstants;
028    import org.jikesrvm.ArchitectureSpecific.ThreadLocalState;
029    import org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants;
030    import org.jikesrvm.ArchitectureSpecific;
031    import org.jikesrvm.Constants;
032    import org.jikesrvm.VM;
033    import org.jikesrvm.Configuration;
034    import org.jikesrvm.Services;
035    import org.jikesrvm.UnimplementedError;
036    import org.jikesrvm.adaptive.OnStackReplacementEvent;
037    import org.jikesrvm.adaptive.measurements.RuntimeMeasurements;
038    import org.jikesrvm.compilers.common.CompiledMethod;
039    import org.jikesrvm.compilers.common.CompiledMethods;
040    import org.jikesrvm.osr.ObjectHolder;
041    import org.jikesrvm.adaptive.OSRListener;
042    import org.jikesrvm.jni.JNIEnvironment;
043    import org.jikesrvm.mm.mminterface.CollectorThread;
044    import org.jikesrvm.mm.mminterface.MemoryManager;
045    import org.jikesrvm.mm.mminterface.ThreadContext;
046    import org.jikesrvm.objectmodel.ObjectModel;
047    import org.jikesrvm.objectmodel.ThinLockConstants;
048    import org.jikesrvm.runtime.Entrypoints;
049    import org.jikesrvm.runtime.Magic;
050    import org.jikesrvm.runtime.Memory;
051    import org.jikesrvm.runtime.RuntimeEntrypoints;
052    import org.jikesrvm.runtime.Time;
053    import org.jikesrvm.runtime.BootRecord;
054    import org.vmmagic.pragma.Inline;
055    import org.vmmagic.pragma.BaselineNoRegisters;
056    import org.vmmagic.pragma.BaselineSaveLSRegisters;
057    import org.vmmagic.pragma.Entrypoint;
058    import org.vmmagic.pragma.Interruptible;
059    import org.vmmagic.pragma.NoInline;
060    import org.vmmagic.pragma.NoOptCompile;
061    import org.vmmagic.pragma.NonMoving;
062    import org.vmmagic.pragma.Uninterruptible;
063    import org.vmmagic.pragma.UninterruptibleNoWarn;
064    import org.vmmagic.pragma.Unpreemptible;
065    import org.vmmagic.pragma.UnpreemptibleNoWarn;
066    import org.vmmagic.pragma.Untraced;
067    import org.vmmagic.pragma.NoCheckStore;
068    import org.vmmagic.unboxed.Address;
069    import org.vmmagic.unboxed.Word;
070    import org.vmmagic.unboxed.Offset;
071    
072    import static org.jikesrvm.runtime.SysCall.sysCall;
073    import org.jikesrvm.classloader.RVMMethod;
074    import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod;
075    import org.jikesrvm.compilers.opt.runtimesupport.OptMachineCodeMap;
076    import org.jikesrvm.compilers.opt.runtimesupport.OptEncodedCallSiteTree;
077    import org.jikesrvm.classloader.MemberReference;
078    import org.jikesrvm.classloader.NormalMethod;
079    import org.jikesrvm.tuningfork.TraceEngine;
080    import org.jikesrvm.tuningfork.Feedlet;
081    
082    /**
083     * A generic java thread's execution context.
084     * <p>
085     * Threads use a state machine to indicate to other threads, as well as VM
086     * services, how this thread should be treated in the case of an asynchronous
087     * request, for example in the case of GC.  The state machine uses the
088     * following states:
089     * <ul>
090     * <li>NEW</li>
091     * <li>IN_JAVA</li>
092     * <li>IN_NATIVE</li>
093     * <li>IN_JNI</li>
094     * <li>IN_JAVA_TO_BLOCK</li>
095     * <li>BLOCKED_IN_NATIVE</li>
096     * <li>BLOCKED_IN_JNI</li>
097     * <li>TERMINATED</li>
098     * </ul>
099     * The following state transitions are legal:
100     * <ul>
101     * <li>NEW to IN_JAVA: occurs when the thread is actually started.  At this
102     *     point it is safe to expect that the thread will reach a safe point in
103     *     some bounded amount of time, at which point it will have a complete
104     *     execution context, and this will be able to have its stack traces by GC.</li>
105     * <li>IN_JAVA to IN_JAVA_TO_BLOCK: occurs when an asynchronous request is
106     *     made, for example to stop for GC, do a mutator flush, or do an isync on PPC.</li>
107     * <li>IN_JAVA to IN_NATIVE: occurs when the code opts to run in privileged mode,
108     *     without synchronizing with GC.  This state transition is only performed by
109     *     HeavyCondLock, in cases where the thread is about to go idle while waiting
110     *     for notifications (such as in the case of park, wait, or sleep).</li>
111     * <li>IN_JAVA to IN_JNI: occurs in response to a JNI downcall, or return from a JNI
112     *     upcall.</li>
113     * <li>IN_JAVA_TO_BLOCK to BLOCKED_IN_NATIVE: occurs when a thread that had been
114     *     asked to perform an async activity decides to go idle instead.  This state
115     *     always corresponds to a notification being sent to other threads, letting
116     *     them know that this thread is idle.  When the thread is idle, any asynchronous
117     *     requests (such as mutator flushes) can instead be performed on behalf of this
118     *     thread by other threads, since this thread is guaranteed not to be running
119     *     any user Java code, and will not be able to return to running Java code without
120     *     first blocking, and waiting to be unblocked (see BLOCKED_IN_NATIVE to IN_JAVA
121     *     transition.</li>
122     * <li>IN_JAVA_TO_BLOCK to BLOCKED_IN_JNI: occurs when a thread that had been
123     *     asked to perform an async activity decides to make a JNI downcall, or return
124     *     from a JNI upcall, instead.  In all other regards, this is identical to the
125     *     IN_JAVA_TO_BLOCK to BLOCKED_IN_NATIVE transition.</li>
126     * <li>IN_NATIVE to IN_JAVA: occurs when a thread returns from idling or running
127     *     privileged code to running Java code.</li>
128     * <li>BLOCKED_IN_NATIVE to IN_JAVA: occurs when a thread that had been asked to
129     *     perform an async activity while running privileged code or idling decides to
130     *     go back to running Java code.  The actual transition is preceded by the
131     *     thread first performing any requested actions (such as mutator flushes) and
132     *     waiting for a notification that it is safe to continue running (for example,
133     *     the thread may wait until GC is finished).</li>
134     * <li>IN_JNI to IN_JAVA: occurs when a thread returns from a JNI downcall, or makes
135     *     a JNI upcall.</li>
136     * <li>BLOCKED_IN_JNI to IN_JAVA: same as BLOCKED_IN_NATIVE to IN_JAVA, except that
137     *     this occurs in response to a return from a JNI downcall, or as the thread
138     *     makes a JNI upcall.</li>
139     * <li>IN_JAVA to TERMINATED: the thread has terminated, and will never reach any
140     *     more safe points, and thus will not be able to respond to any more requests
141     *     for async activities.</li>
142     * </ul>
143     * Observe that the transitions from BLOCKED_IN_NATIVE and BLOCKED_IN_JNI to IN_JAVA
144     * constitute a safe point.  Code running in BLOCKED_IN_NATIVE or BLOCKED_IN_JNI is
145     * "GC safe" but is not quite at a safe point; safe points are special in that
146     * they allow the thread to perform async activities (such as mutator flushes or
147     * isyncs), while GC safe code will not necessarily perform either.
148     *
149     * @see org.jikesrvm.mm.mminterface.CollectorThread
150     * @see FinalizerThread
151     * @see org.jikesrvm.adaptive.measurements.organizers.Organizer
152     */
153    @Uninterruptible
154    @NonMoving
155    public final class RVMThread extends ThreadContext implements Constants {
156      /*
157       * debug and statistics
158       */
159      /** Trace thread blockage */
160      protected static final boolean traceBlock = false;
161    
162      /** Trace when a thread is really blocked */
163      protected static final boolean traceReallyBlock = false || traceBlock;
164    
165      protected static final boolean traceAboutToTerminate = false;
166    
167      protected static final boolean dumpStackOnBlock = false; // DANGEROUS! can lead to crashes!
168    
169      protected static final boolean traceBind = false;
170    
171      /** Trace thread start/stop */
172      protected static final boolean traceAcct = false;
173    
174      /** Trace execution */
175      protected static final boolean trace = false;
176    
177      /** Trace thread termination */
178      private static final boolean traceTermination = false;
179    
180      /** Trace adjustments to stack size */
181      private static final boolean traceAdjustments = false;
182    
183      /** Never kill threads.  Useful for testing bugs related to interaction of
184          thread death with for example MMTk.  For production, this should never
185          be set to true. */
186      private static final boolean neverKillThreads = false;
187    
188      /** Generate statistics? */
189      private static final boolean STATS = Lock.STATS;
190    
191      /** Number of wait operations */
192      static int waitOperations;
193    
194      /** Number of timed wait operations */
195      static int timedWaitOperations;
196    
197      /** Number of notify operations */
198      static int notifyOperations;
199    
200      /** Number of notifyAll operations */
201      static int notifyAllOperations;
202    
203      public static final boolean ALWAYS_LOCK_ON_STATE_TRANSITION = false;
204    
205      /*
206       * definitions for thread status for interaction of Java-native transitions
207       * and requests for threads to stop.  THESE ARE PRIVATE TO THE SCHEDULER, and
208       * are only used deep within the stack.
209       */
210      /**
211       * Thread has not yet started. This state holds right up until just before we
212       * call pthread_create().
213       */
214      public static final int NEW = 0;
215    
216      /** Thread is executing "normal" Java bytecode */
217      public static final int IN_JAVA = 1;
218    
219      /**
220       * A state used by the scheduler to mark that a thread is in privileged code
221       * that does not need to synchronize with the collector.  This is a special
222       * state, similar to the IN_JNI state but requiring different interaction with
223       * the collector (as there is no JNI stack frame, the registers have to be
224       * saved in contextRegisters).  As well, this state should only be entered
225       * from privileged code in the org.jikesrvm.scheduler package.  Typically,
226       * this state is entered using a call to enterNative() just prior to idling
227       * the thread; though it would not be wrong to enter it prior to any other
228       * long-running activity that does not require interaction with the GC.
229       */
230      public static final int IN_NATIVE = 2;
231    
232      /**
233       * Same as IN_NATIVE, except that we're executing JNI code and thus have a
234       * JNI stack frame and JNI environment, and thus the GC can load registers
235       * from there rather than using contextRegisters.
236       */
237      public static final int IN_JNI = 3;
238    
239      /**
240       * thread is in Java code but is expected to block. the transition from IN_JAVA
241       * to IN_jAVA_TO_BLOCK happens as a result of an asynchronous call by the GC
242       * or any other internal VM code that requires this thread to perform an
243       * asynchronous activity (another example is the request to do an isync on PPC).
244       * the point is that we're waiting for the thread to reach a safe point and
245       * expect this to happen in bounded time; but if the thread were to escape to
246       * native we want to know about it. thus, transitions into native code while
247       * in the IN_JAVA_TO_BLOCK state result in a notification (broadcast on the
248       * thread's monitor) and a state change to BLOCKED_IN_NATIVE. Observe that it
249       * is always safe to conservatively change IN_JAVA to IN_JAVA_TO_BLOCK.
250       */
251      public static final int IN_JAVA_TO_BLOCK = 4;
252    
253      /**
254       * thread is in native code, and is to block before returning to Java code.
255       * the transition from IN_NATIVE to BLOCKED_IN_NATIVE happens as a result
256       * of an asynchronous call by the GC or any other internal VM code that
257       * requires this thread to perform an asynchronous activity (another example
258       * is the request to do an isync on PPC).  as well, code entering privileged
259       * code that would otherwise go from IN_JAVA to IN_NATIVE will go to
260       * BLOCKED_IN_NATIVE instead, if the state was IN_JAVA_TO_BLOCK.
261       * <p>
262       * the point of this state is that the thread is guaranteed not to execute
263       * any Java code until:
264       * <ol>
265       * <li>The state changes to IN_NATIVE, and
266       * <li>The thread gets a broadcast on its monitor.
267       * </ol>
268       * Observe that it is always safe to conservatively change IN_NATIVE to
269       * BLOCKED_IN_NATIVE.
270       */
271      public static final int BLOCKED_IN_NATIVE = 5;
272    
273      /**
274       * like BLOCKED_IN_NATIVE, but indicates that the thread is in JNI rather than
275       * VM native code.
276       */
277      public static final int BLOCKED_IN_JNI = 6;
278    
279      /**
280       * Thread has died. As in, it's no longer executing any Java code and will
281       * never do so in the future. Once this is set, the GC will no longer mark any
282       * part of the thread as live; the thread's stack will be deleted. Note that
283       * this is distinct from the aboutToTerminate state.
284       */
285      public static final int TERMINATED = 7;
286    
287      /** Not actually a state but just a marker. */
288      public static final int LAST_EXEC_STATUS = 8;
289    
290      public static boolean notRunning(int state) {
291        return state == NEW || state == TERMINATED;
292      }
293    
294      /** Registers used by return barrier trampoline */
295      private Registers trampolineRegisters = new Registers();
296    
297      /** Return address of stack frame hijacked by return barrier */
298      private Address hijackedReturnAddress;
299    
300      /** Callee frame pointer for stack frame hijacked by return barrier */
301      private Address hijackedReturnCalleeFp = Address.zero();
302    
303      /** Caller frame pointer for stack frame hijacked by return barrier */
304      private Address hijackedReturnCallerFp = ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP;
305    
306      /** @return the callee frame pointer for the stack frame hijacked by the return barrier */
307      public Address getHijackedReturnCalleeFp() { return hijackedReturnCalleeFp; }
308    
309      /** debugging flag for return barrier trampoline */
310      public static final boolean DEBUG_STACK_TRAMPOLINE = false;
311    
312      /** pointer to bridge code for return barrier trampoline */
313      public static ArchitectureSpecific.CodeArray stackTrampolineBridgeInstructions;
314    
315      /**
316       * Thread state. Indicates if the thread is running, and if so, what mode of
317       * execution it is using (Java, VM native, or JNI)
318       */
319      @Entrypoint
320      private int execStatus;
321    
322      public int getExecStatus() {
323        observeExecStatus();
324        return execStatus;
325      }
326    
327      private boolean attemptFastExecStatusTransition(int oldState,
328                                                      int newState) {
329        if (Synchronization.tryCompareAndSwap(
330              this,
331              Entrypoints.execStatusField.getOffset(),
332              oldState,
333              newState)) {
334          observeStateTransition(oldState,newState);
335          return true;
336        } else {
337          return false;
338        }
339      }
340    
341      // call this only when holding the lock or if you really know what you're
342      // doing.
343      private void setExecStatus(int newState) {
344        observeStateTransition(execStatus,newState);
345        execStatus=newState;
346      }
347    
348      /**
349       * Is the thread about to terminate? Protected by the thread's monitor. Note
350       * that this field is not set atomically with the entering of the thread onto
351       * the aboutToTerminate array - in fact it happens before that. When this
352       * field is set to true, the thread's stack will no longer be scanned by GC.
353       * Note that this is distinct from the TERMINATED state.
354       */
355      // FIXME: there should be an execStatus state called TERMINATING that
356      // corresponds to this. that would make a lot more sense.
357      private boolean isAboutToTerminate;
358    
359      public boolean getIsAboutToTerminate() { return isAboutToTerminate; }
360    
361      /** Is this thread in the process of blocking? */
362      boolean isBlocking;
363    
364      /**
365       * Is the thread no longer executing user code? Protected by the Java monitor
366       * associated with the Thread object.
367       */
368      boolean isJoinable;
369    
370      /**
371       * Link pointer for queues (specifically ThreadQueue). A thread can only be
372       * on one such queue at a time. The queue that a thread is on is indicated by
373       * <code>queuedOn</code>.
374       */
375      @Untraced
376      RVMThread next;
377    
378      /**
379       * The queue that the thread is on, or null if the thread is not on a queue
380       * (specifically ThreadQueue). If the thread is on such a queue, the
381       * <code>next</code> field is used as a link pointer.
382       */
383      @Untraced
384      volatile ThreadQueue queuedOn;
385    
386      /**
387       * @return True if this thread is currently on a queue.
388       */
389      public boolean isOnQueue() {
390        return queuedOn != null;
391      }
392    
393      /**
394       * Used to handle contention for spin locks
395       */
396      @Untraced
397      SpinLock awaitingSpinLock;
398    
399      @Untraced
400      RVMThread contenderLink;
401    
402      /**
403       * java.lang.Thread wrapper for this Thread. Not final so it may be assigned
404       * during booting
405       */
406      private Thread thread;
407    
408      /** Name of the thread (can be changed during execution) */
409      private String name;
410    
411      /**
412       * The virtual machine terminates when the last non-daemon (user) thread
413       * terminates.
414       */
415      protected boolean daemon;
416    
417      /**
418       * Scheduling priority for this thread. Note that:
419       * {@link java.lang.Thread#MIN_PRIORITY} <= priority <=
420       * {@link java.lang.Thread#MAX_PRIORITY}.
421       */
422      private int priority;
423    
424      /**
425       * Index of this thread in {@link #threadBySlot}[]. This value must be non-zero
426       * because it is shifted and used in {@link Object} lock ownership tests.
427       */
428      @Entrypoint
429      public int threadSlot;
430    
431      public int lockingId;
432    
433      /**
434       * Non-null indicates this is a system thread, that is one used by the system and as such
435       * doesn't have a Runnable...
436       */
437      private final SystemThread systemThread;
438    
439      /**
440       * The boot thread, can't be final so as to allow initialization during boot
441       * image writing.
442       */
443      @Entrypoint
444      public static RVMThread bootThread;
445    
446      /**
447       * Is the threading system initialized?
448       */
449      public static boolean threadingInitialized = false;
450    
451      /**
452       * Number of timer ticks we've seen
453       */
454      public static long timerTicks;
455    
456      private long yieldpointsTaken;
457    
458      private long yieldpointsTakenFully;
459    
460      private long nativeEnteredBlocked;
461    
462      private long jniEnteredBlocked;
463    
464      /**
465       * Assertion checking while manipulating raw addresses -- see
466       * {@link VM#disableGC()}/{@link VM#enableGC()}. A value of "true" means
467       * it's an error for this thread to call "new". This is only used for
468       * assertion checking; we do not bother to set it when
469       * {@link VM#VerifyAssertions} is false.
470       */
471      private boolean disallowAllocationsByThisThread;
472    
473      /**
474       * Counts the depth of outstanding calls to {@link VM#disableGC()}. If this
475       * is set, then we should also have {@link #disallowAllocationsByThisThread}
476       * set. The converse also holds.
477       */
478      private int disableGCDepth = 0;
479    
480      public int barriersEntered = 0;
481    
482      public int barriersExited = 0;
483    
484      /**
485       * Execution stack for this thread.
486       */
487      @Entrypoint
488      private byte[] stack;
489    
490      /** The {@link Address} of the guard area for {@link #stack}. */
491      @Entrypoint
492      public Address stackLimit;
493    
494      /* --------- BEGIN IA-specific fields. NOTE: NEED TO REFACTOR --------- */
495      // On powerpc, these values are in dedicated registers,
496      // we don't have registers to burn on IA32, so we indirect
497      // through the TR register to get them instead.
498      /**
499       * FP for current frame, saved in the prologue of every method
500       */
501      Address framePointer;
502    
503      /**
504       * "hidden parameter" for interface invocation thru the IMT
505       */
506      int hiddenSignatureId;
507    
508      /**
509       * "hidden parameter" from ArrayIndexOutOfBounds trap to C trap handler
510       */
511      int arrayIndexTrapParam;
512    
513      /* --------- END IA-specific fields. NOTE: NEED TO REFACTOR --------- */
514    
515      /**
516       * Is the next taken yieldpoint in response to a request to perform OSR?
517       */
518      public boolean yieldToOSRRequested;
519    
520      /**
521       * Is CBS enabled for 'call' yieldpoints?
522       */
523      public boolean yieldForCBSCall;
524    
525      /**
526       * Is CBS enabled for 'method' yieldpoints?
527       */
528      public boolean yieldForCBSMethod;
529    
530      /**
531       * Number of CBS samples to take in this window
532       */
533      public int numCBSCallSamples;
534    
535      /**
536       * Number of call yieldpoints between CBS samples
537       */
538      public int countdownCBSCall;
539    
540      /**
541       * round robin starting point for CBS samples
542       */
543      public int firstCBSCallSample;
544    
545      /**
546       * Number of CBS samples to take in this window
547       */
548      public int numCBSMethodSamples;
549    
550      /**
551       * Number of counter ticks between CBS samples
552       */
553      public int countdownCBSMethod;
554    
555      /**
556       * round robin starting point for CBS samples
557       */
558      public int firstCBSMethodSample;
559    
560      /* --------- BEGIN PPC-specific fields. NOTE: NEED TO REFACTOR --------- */
561      /**
562       * flag indicating this processor needs to execute a memory synchronization
563       * sequence Used for code patching on SMP PowerPCs.
564       */
565      public boolean codePatchSyncRequested;
566    
567      /* --------- END PPC-specific fields. NOTE: NEED TO REFACTOR --------- */
568    
569      /**
570       * For builds using counter-based sampling. This field holds a
571       * processor-specific counter so that it can be updated efficiently on SMP's.
572       */
573      public int thread_cbs_counter;
574    
575      /**
576       * Should this thread yield at yieldpoints? A value of: 1 means "yes"
577       * (yieldpoints enabled) <= 0 means "no" (yieldpoints disabled)
578       */
579      private int yieldpointsEnabledCount;
580    
581      /**
582       * Is a takeYieldpoint request pending on this thread?
583       */
584      boolean yieldpointRequestPending;
585    
586      /**
587       * Are we at a yieldpoint right now?
588       */
589      boolean atYieldpoint;
590    
591      /**
592       * Is there a flush request for this thread? This is handled via a soft
593       * handshake.
594       */
595      public boolean flushRequested;
596    
597      /**
598       * Is a soft handshake requested? Logically, this field is protected by the
599       * thread's monitor - but it is typically only mucked with when both the
600       * thread's monitor and the softHandshakeDataLock are held.
601       */
602      public boolean softHandshakeRequested;
603    
604      /**
605       * How many threads have not yet reached the soft handshake? (protected by
606       * softHandshakeDataLock)
607       */
608      public static int softHandshakeLeft;
609    
610      /**
611       * Lock that protects soft handshake fields.
612       */
613      public static Monitor softHandshakeDataLock;
614    
615      /**
616       * Lock that prevents multiple (soft or hard) handshakes from proceeding
617       * concurrently.
618       */
619      public static Monitor handshakeLock;
620    
621      /**
622       * Place to save register state when this thread is not actually running.
623       */
624      @Entrypoint
625      @Untraced
626      public final Registers contextRegisters;
627      @SuppressWarnings("unused")
628      private final Registers contextRegistersShadow;
629    
630      /**
631       * Place to save register state when this thread is not actually running.
632       */
633      @Entrypoint
634      @Untraced
635      public final Registers contextRegistersSave;
636      @SuppressWarnings("unused")
637      private final Registers contextRegistersSaveShadow;
638    
639      /**
640       * Place to save register state during hardware(C signal trap handler) or
641       * software (RuntimeEntrypoints.athrow) trap handling.
642       */
643      @Entrypoint
644      @Untraced
645      private final Registers exceptionRegisters;
646      @SuppressWarnings("unused")
647      private final Registers exceptionRegistersShadow;
648    
649      /** Count of recursive uncaught exceptions, we need to bail out at some point */
650      private int uncaughtExceptionCount = 0;
651    
652      /**
653       * A cached free lock. Not a free list; this will only ever contain 0 or 1
654       * locks!
655       */
656      public Lock cachedFreeLock;
657    
658      /*
659       * Wait/notify fields
660       */
661    
662      /**
663       * Place to save/restore this thread's monitor state during
664       * {@link Object#wait} and {@link Object#notify}.
665       */
666      protected Object waitObject;
667    
668      /** Lock recursion count for this thread's monitor. */
669      protected int waitCount;
670    
671      /**
672       * Should the thread suspend?
673       */
674      boolean shouldSuspend;
675    
676      /**
677       * An integer token identifying the last suspend request
678       */
679      int shouldSuspendToken;
680    
681      /**
682       * Is the thread suspended?
683       */
684      boolean isSuspended;
685    
686      /**
687       * Should the thread block for handshake?
688       */
689      boolean shouldBlockForHandshake;
690    
691      /**
692       * Is the thread blocked for handshake?
693       */
694      boolean isBlockedForHandshake;
695    
696      /**
697       * Should the thread block for a thread-to-thread communication?
698       */
699      boolean shouldBlockForGC;
700    
701      /**
702       * Is the thread blocked for thread-to-thread communication?
703       */
704      boolean isBlockedForGC;
705    
706      /**
707       * A block adapter specifies the reason for blocking or unblocking a thread.  A thread
708       * remains blocked so long as any of the block adapters say that it should be blocked.
709       * Block adapters are statically allocated, and store their state in instance fields of
710       * RVMThread.
711       */
712      @Uninterruptible
713      @NonMoving
714      public abstract static class BlockAdapter {
715        /** Should the given thread be blocked for this block adapter?  If this returns true,
716            the thread is guaranteed to block. */
717        abstract boolean isBlocked(RVMThread t);
718    
719        /** Specify that the thread is either blocked (value == true) or not blocked
720            (value == false) for this block adapter.  This call indicates a statement of
721            fact by the thread itself - it's used either to acknowledge a block request
722            (see hasBlockRequest below) or to respond to a request to unblock. */
723        abstract void setBlocked(RVMThread t, boolean value);
724    
725        /** Request that the thread block, for this block adapter, at its earliest
726            convenience.  Called from RVMThread.block() and associated methods.  Some
727            block adapters allow for multiple requests to block; in that case this will
728            return a "token" that can be passed to hasBlockRequest() to check, not only
729            whether there is a block request, but whether that block request is still
730            associated with a particular call to requestBlock().  This is used to prevent
731            a suspend() call from stalling due to a concurrent resume() and second
732            suspend().  Note that most block adapers don't care about this scenario, and
733            will just return 0 (or some other meaningless number) here. */
734        abstract int requestBlock(RVMThread t);
735    
736        /** Does the thread have a request to block for this block adapter? */
737        abstract boolean hasBlockRequest(RVMThread t);
738    
739        /** Does the thread have a request to block associated with the given requestBlock()
740            call? */
741        abstract boolean hasBlockRequest(RVMThread t, int token);
742    
743        /** Clear any blocking requests. */
744        abstract void clearBlockRequest(RVMThread t);
745      }
746    
747      @Uninterruptible
748      @NonMoving
749      public static class SuspendBlockAdapter extends BlockAdapter {
750        @Override
751        boolean isBlocked(RVMThread t) {
752          return t.isSuspended;
753        }
754    
755        @Override
756        void setBlocked(RVMThread t, boolean value) {
757          t.isSuspended = value;
758        }
759    
760        @Override
761        int requestBlock(RVMThread t) {
762          if (t.isSuspended || t.shouldSuspend) {
763            return t.shouldSuspendToken;
764          } else {
765            t.shouldSuspend = true;
766            t.shouldSuspendToken++;
767            return t.shouldSuspendToken;
768          }
769        }
770    
771        @Override
772        boolean hasBlockRequest(RVMThread t) {
773          return t.shouldSuspend;
774        }
775    
776        @Override
777        boolean hasBlockRequest(RVMThread t, int token) {
778          return t.shouldSuspend && t.shouldSuspendToken == token;
779        }
780    
781        @Override
782        void clearBlockRequest(RVMThread t) {
783          t.shouldSuspend = false;
784        }
785      }
786    
787      public static final SuspendBlockAdapter suspendBlockAdapter = new SuspendBlockAdapter();
788    
789      @Uninterruptible
790      @NonMoving
791      public static class HandshakeBlockAdapter extends BlockAdapter {
792        @Override
793        boolean isBlocked(RVMThread t) {
794          return t.isBlockedForHandshake;
795        }
796    
797        @Override
798        void setBlocked(RVMThread t, boolean value) {
799          t.isBlockedForHandshake = value;
800        }
801    
802        @Override
803        int requestBlock(RVMThread t) {
804          if (!t.isBlockedForHandshake) {
805            t.shouldBlockForHandshake = true;
806          }
807          return 0;
808        }
809    
810        @Override
811        boolean hasBlockRequest(RVMThread t) {
812          return t.shouldBlockForHandshake;
813        }
814    
815        @Override
816        boolean hasBlockRequest(RVMThread t, int token) {
817          return t.shouldBlockForHandshake;
818        }
819    
820        @Override
821        void clearBlockRequest(RVMThread t) {
822          t.shouldBlockForHandshake = false;
823        }
824      }
825    
826      public static final HandshakeBlockAdapter handshakeBlockAdapter = new HandshakeBlockAdapter();
827    
828      @Uninterruptible
829      @NonMoving
830      public static class GCBlockAdapter extends BlockAdapter {
831        @Override
832        boolean isBlocked(RVMThread t) {
833          return t.isBlockedForGC;
834        }
835    
836        @Override
837        void setBlocked(RVMThread t, boolean value) {
838          t.isBlockedForGC = value;
839        }
840    
841        @Override
842        int requestBlock(RVMThread t) {
843          if (!t.isBlockedForGC) {
844            t.shouldBlockForGC = true;
845          }
846          return 0;
847        }
848    
849        @Override
850        boolean hasBlockRequest(RVMThread t) {
851          return t.shouldBlockForGC;
852        }
853    
854        @Override
855        boolean hasBlockRequest(RVMThread t, int token) {
856          return t.shouldBlockForGC;
857        }
858    
859        @Override
860        void clearBlockRequest(RVMThread t) {
861          t.shouldBlockForGC = false;
862        }
863      }
864    
865      public static final GCBlockAdapter gcBlockAdapter = new GCBlockAdapter();
866    
867      static final BlockAdapter[] blockAdapters = new BlockAdapter[] {
868        suspendBlockAdapter, handshakeBlockAdapter, gcBlockAdapter };
869    
870      /**
871       * An enumeration that describes the different manners in which a thread might
872       * be voluntarily waiting.
873       */
874      protected static enum Waiting {
875        /** The thread is not waiting at all. In fact it's running. */
876        RUNNABLE,
877        /** The thread is waiting without a timeout. */
878        WAITING,
879        /** The thread is waiting with a timeout. */
880        TIMED_WAITING
881      }
882    
883      /**
884       * Accounting of whether or not a thread is waiting (in the Java thread state
885       * sense), and if so, how it's waiting.
886       * <p>
887       * Invariant: the RVM runtime does not ever use this field for any purpose
888       * other than updating it so that the java.lang.Thread knows the state. Thus,
889       * if you get sloppy with this field, the worst case outcome is that some Java
890       * program that queries the thread state will get something other than what it
891       * may or may not have expected.
892       */
893      protected Waiting waiting;
894    
895      /**
896       * Exception to throw in this thread at the earliest possible point.
897       */
898      Throwable asyncThrowable;
899    
900      /**
901       * Has the thread been interrupted?
902       */
903      boolean hasInterrupt;
904    
905      /**
906       * Should the next executed yieldpoint be taken? Can be true for a variety of
907       * reasons. See RVMThread.yieldpoint
908       * <p>
909       * To support efficient sampling of only prologue/epilogues we also encode
910       * some extra information into this field. 0 means that the yieldpoint should
911       * not be taken. >0 means that the next yieldpoint of any type should be taken
912       * <0 means that the next prologue/epilogue yieldpoint should be taken
913       * <p>
914       * Note the following rules:
915       * <ol>
916       * <li>If takeYieldpoint is set to 0 or -1 it is perfectly safe to set it to
917       * 1; this will have almost no effect on the system. Thus, setting
918       * takeYieldpoint to 1 can always be done without acquiring locks.</li>
919       * <li>Setting takeYieldpoint to any value other than 1 should be done while
920       * holding the thread's monitor().</li>
921       * <li>The exception to rule (2) above is that the yieldpoint itself sets
922       * takeYieldpoint to 0 without holding a lock - but this is done after it
923       * ensures that the yieldpoint is deferred by setting yieldpointRequestPending
924       * to true.
925       * </ol>
926       */
927      @Entrypoint
928      public int takeYieldpoint;
929    
930      /**
931       * How many times has the "timeslice" expired? This is only used for profiling
932       * and OSR (in particular base-to-opt OSR).
933       */
934      public int timeSliceExpired;
935    
936      /** Is a running thread permitted to ignore the next park request */
937      private boolean parkingPermit;
938    
939      /*
940       * JNI fields
941       */
942    
943      /**
944       * Cached JNI environment for this thread
945       */
946      @Entrypoint
947      @Untraced
948      private JNIEnvironment jniEnv;
949      @SuppressWarnings("unused")
950      private JNIEnvironment jniEnvShadow;
951    
952      /** Used by GC to determine collection success */
953      private boolean physicalAllocationFailed;
954    
955      /** Used by GC to determine collection success */
956      private int collectionAttempt;
957    
958      /** The OOME to throw */
959      private static OutOfMemoryError outOfMemoryError;
960    
961      /*
962       * Enumerate different types of yield points for sampling
963       */
964      public static final int PROLOGUE = 0;
965    
966      public static final int BACKEDGE = 1;
967    
968      public static final int EPILOGUE = 2;
969    
970      public static final int NATIVE_PROLOGUE = 3;
971    
972      public static final int NATIVE_EPILOGUE = 4;
973    
974      public static final int OSROPT = 5;
975    
976      /*
977       * Fields used for on stack replacement
978       */
979    
980      /**
981       * Only used by OSR when VM.BuildForAdaptiveSystem. Declared as an Object to
982       * cut link to adaptive system. Ugh.
983       */
984      public final Object /* OnStackReplacementEvent */onStackReplacementEvent;
985    
986      /**
987       * The flag indicates whether this thread is waiting for on stack replacement
988       * before being rescheduled.
989       */
990      // flags should be packaged or replaced by other solutions
991      public boolean isWaitingForOsr = false;
992    
993      /**
994       * Before call new instructions, we need a bridge to recover register states
995       * from the stack frame.
996       */
997      public CodeArray bridgeInstructions = null;
998    
999      /** Foo frame pointer offset */
1000      public Offset fooFPOffset = Offset.zero();
1001    
1002      /** Thread switch frame pointer offset */
1003      public Offset tsFPOffset = Offset.zero();
1004    
1005      /**
1006       * Flag to synchronize with osr organizer, the trigger sets osr requests the
1007       * organizer clear the requests
1008       */
1009      public boolean requesting_osr = false;
1010    
1011      /**
1012       * Flag to indicate that the last OSR request is done.
1013       */
1014      public boolean osr_done = false;
1015    
1016      /**
1017       * The number of processors to use.
1018       */
1019      public static int availableProcessors = -1;
1020    
1021      /**
1022       * Thread handle. Currently stores pthread_t, which we assume to be no larger
1023       * than a pointer-sized word.
1024       */
1025      public Word pthread_id;
1026    
1027      /**
1028       * Scratch area for use for gpr <=> fpr transfers by PPC baseline compiler.
1029       * Used to transfer x87 to SSE registers on IA32
1030       */
1031      @SuppressWarnings({ "unused" })
1032      // accessed via EntryPoints
1033      private double scratchStorage;
1034    
1035      /**
1036       * Current index of this thread in the threads array. This may be changed by
1037       * another thread, but only while the acctLock is held.
1038       */
1039      private int threadIdx;
1040    
1041      /**
1042       * Is the system in the process of shutting down (has System.exit been called)
1043       */
1044      private static boolean systemShuttingDown = false;
1045    
1046      /**
1047       * Flag set by external signal to request debugger activation at next thread
1048       * switch. See also: RunBootImage.C
1049       */
1050      public static volatile boolean debugRequested;
1051    
1052      public volatile boolean asyncDebugRequestedForThisThread;
1053    
1054      /**
1055       * The latch for reporting profile data.
1056       */
1057      public static Latch doProfileReport;
1058    
1059      /** Number of times dump stack has been called recursively */
1060      protected int inDumpStack = 0;
1061    
1062      /** Is this a "registered mutator?" */
1063      public boolean activeMutatorContext = false;
1064    
1065      /** Lock used for dumping stack and such. */
1066      public static Monitor dumpLock;
1067    
1068      /** In dump stack and dying */
1069      protected static boolean exitInProgress = false;
1070    
1071      private static boolean worldStopped;
1072    
1073      /** Extra debug from traces */
1074      protected static final boolean traceDetails = false;
1075    
1076      /** Toggle display of frame pointer address in stack dump */
1077      private static final boolean SHOW_FP_IN_STACK_DUMP = true;
1078    
1079      /** Index of thread in which "VM.boot()" runs */
1080      public static final int PRIMORDIAL_THREAD_INDEX = 1;
1081    
1082      /** Maximum number of RVMThread's that we can support. */
1083      public static final int LOG_MAX_THREADS = 10;
1084    
1085      public static final int MAX_THREADS = 1 << LOG_MAX_THREADS;
1086    
1087      /**
1088       * thread array - all threads are stored in this array according to their
1089       * threadSlot.
1090       */
1091      public static RVMThread[] threadBySlot = new RVMThread[MAX_THREADS];
1092    
1093      /**
1094       * Per-thread monitors. Note that this array is statically initialized. It
1095       * starts out all null. When a new thread slot is allocated, a monitor is
1096       * added for that slot.
1097       * <p>
1098       * Question: what is the outcome, if any, of taking a yieldpoint while holding
1099       * this lock?
1100       * <ol>
1101       * <li>If there is a GC request we will wait on this condition variable and
1102       * thus release it. Someone else might then acquire the lock before realizing
1103       * that there is a GC request and then do bad things.</li>
1104       * <li>The yieldpoint might acquire another thread's monitor. Thus, two
1105       * threads may get into lock inversion with each other.</li>
1106       * <li>???</li>
1107       * </ol>
1108       */
1109      private static final NoYieldpointsMonitor[] monitorBySlot = new NoYieldpointsMonitor[MAX_THREADS];
1110    
1111      private static final Monitor[] communicationLockBySlot = new Monitor[MAX_THREADS];
1112    
1113      /**
1114       * Lock (mutex) used for creating and destroying threads as well as thread
1115       * accounting.  This mutex should not be held while thread monitors (see monitorBySlot)
1116       * are held.  Use this mutex only to protect accesses to:
1117       * <ul>
1118       * <li>the global thread lists, such as threadBySlot, aboutToTerminate, threads, and
1119       *     freeLots</li>
1120       * <li>threadIdx field of RVMThread</li>
1121       * <li>numThreads, numActiveThreads, numActiveDaemons static fields of RVMThread</li>
1122       * </ul>
1123       */
1124      public static NoYieldpointsMonitor acctLock;
1125    
1126      /**
1127       * Lock (mutex) used for servicing debug requests.
1128       */
1129      public static NoYieldpointsMonitor debugLock;
1130    
1131      /**
1132       * Lock used for generating debug output.
1133       */
1134      private static NoYieldpointsMonitor outputLock;
1135    
1136      /**
1137       * Thread slots of threads that are about to terminate.  This must be
1138       * an int array because it's accessed from code that cannot have
1139       * barriers.
1140       */
1141      private static final int[] aboutToTerminate = new int[MAX_THREADS];
1142    
1143      /**
1144       * Number of threads that are about to terminate.
1145       */
1146      private static int aboutToTerminateN;
1147    
1148      /**
1149       * Free thread slots
1150       */
1151      private static final int[] freeSlots = new int[MAX_THREADS];
1152    
1153      /**
1154       * Number of free thread slots.
1155       */
1156      private static int freeSlotN;
1157    
1158      /**
1159       * When there are no thread slots on the free list, this is the next one to
1160       * use.
1161       */
1162      public static int nextSlot = 2;
1163    
1164      /**
1165       * Number of threads in the system (some of which may not be active).
1166       */
1167      public static int numThreads;
1168    
1169      /**
1170       * Packed and unordered array or active threads. Only entries in the range 0
1171       * to numThreads-1 (inclusive) are defined. Note that it should be possible to
1172       * scan this array without locking and get all of the threads - but only if
1173       * you scan downward and place a memory fence between loads.
1174       * <p>
1175       * Note further that threads remain in this array even after the Java
1176       * libraries no longer consider the thread to be active.
1177       */
1178      public static final RVMThread[] threads = new RVMThread[MAX_THREADS];
1179    
1180      /**
1181       * Preallocated array for use in handshakes. Protected by handshakeLock.
1182       */
1183      public static final RVMThread[] handshakeThreads = new RVMThread[MAX_THREADS];
1184    
1185      /**
1186       * Preallocated array for use in debug requested. Protected by debugLock.
1187       */
1188      public static final RVMThread[] debugThreads = new RVMThread[MAX_THREADS];
1189    
1190      /**
1191       * Number of active threads in the system.
1192       */
1193      private static int numActiveThreads;
1194    
1195      /**
1196       * Number of active daemon threads.
1197       */
1198      private static int numActiveDaemons;
1199    
1200      /*
1201       * TuningFork instrumentation support
1202       */
1203      /**
1204       * The Feedlet instance for this thread to use to make addEvent calls.
1205       */
1206      public Feedlet feedlet;
1207    
1208      /**
1209       * Get a NoYieldpointsCondLock for a given thread slot.
1210       */
1211      static NoYieldpointsMonitor monitorForSlot(int slot) {
1212        NoYieldpointsMonitor result = monitorBySlot[slot];
1213        if (VM.VerifyAssertions)
1214          VM._assert(result != null);
1215        return result;
1216      }
1217    
1218      /**
1219       * Get the NoYieldpointsCondLock for this thread.
1220       */
1221      public NoYieldpointsMonitor monitor() {
1222        return monitorForSlot(threadSlot);
1223      }
1224    
1225      public Monitor communicationLockForSlot(int slot) {
1226        Monitor result = communicationLockBySlot[slot];
1227        if (VM.VerifyAssertions)
1228          VM._assert(result != null);
1229        return result;
1230      }
1231    
1232      public Monitor communicationLock() {
1233        return communicationLockForSlot(threadSlot);
1234      }
1235    
1236      /**
1237       * Initialize the threading subsystem for the boot image.
1238       */
1239      @Interruptible
1240      public static void init() {
1241        // Enable us to dump a Java Stack from the C trap handler to aid in
1242        // debugging things that
1243        // show up as recursive use of hardware exception registers (eg the
1244        // long-standing lisp bug)
1245        BootRecord.the_boot_record.dumpStackAndDieOffset =
1246          Entrypoints.dumpStackAndDieMethod.getOffset();
1247        Lock.init();
1248      }
1249    
1250      public void assertAcceptableStates(int expected) {
1251        if (VM.VerifyAssertions) {
1252          int curStatus=getExecStatus();
1253          if (curStatus!=expected) {
1254            VM.sysWriteln("FATAL ERROR: unexpected thread state.");
1255            VM.sysWriteln("Expected: ",expected);
1256            VM.sysWriteln("Observed: ",curStatus);
1257            VM._assert(curStatus==expected);
1258          }
1259        }
1260      }
1261    
1262      public void assertAcceptableStates(int expected1,int expected2) {
1263        if (VM.VerifyAssertions) {
1264          int curStatus=getExecStatus();
1265          if (curStatus!=expected1 &&
1266              curStatus!=expected2) {
1267            VM.sysWriteln("FATAL ERROR: unexpected thread state.");
1268            VM.sysWriteln("Expected: ",expected1);
1269            VM.sysWriteln("      or: ",expected2);
1270            VM.sysWriteln("Observed: ",curStatus);
1271            VM._assert(curStatus==expected1 ||
1272                       curStatus==expected2);
1273          }
1274        }
1275      }
1276    
1277      public void assertUnacceptableStates(int unexpected) {
1278        if (VM.VerifyAssertions) {
1279          int curStatus=getExecStatus();
1280          if (curStatus==unexpected) {
1281            VM.sysWriteln("FATAL ERROR: unexpected thread state.");
1282            VM.sysWriteln("Unexpected: ",unexpected);
1283            VM.sysWriteln("  Observed: ",curStatus);
1284            VM._assert(curStatus!=unexpected);
1285          }
1286        }
1287      }
1288    
1289      public void assertUnacceptableStates(int unexpected1,int unexpected2) {
1290        if (VM.VerifyAssertions) {
1291          int curStatus=getExecStatus();
1292          if (curStatus==unexpected1 ||
1293              curStatus==unexpected2) {
1294            VM.sysWriteln("FATAL ERROR: unexpected thread state for thread", threadSlot);
1295            VM.sysWriteln("Unexpected: ",unexpected1);
1296            VM.sysWriteln("       and: ",unexpected2);
1297            VM.sysWriteln("  Observed: ",curStatus);
1298            VM._assert(curStatus!=unexpected1 &&
1299                       curStatus!=unexpected2);
1300          }
1301        }
1302      }
1303    
1304      static void bind(int cpuId) {
1305        if (VM.VerifyAssertions) VM._assert(sysCall.sysThreadBindSupported()==1);
1306        sysCall.sysThreadBind(cpuId);
1307      }
1308    
1309      static void bindIfRequested() {
1310        if (VM.forceOneCPU>=0) {
1311          if (traceBind) {
1312            VM.sysWriteln("binding thread to CPU: ",VM.forceOneCPU);
1313          }
1314          bind(VM.forceOneCPU);
1315        }
1316      }
1317    
1318      /**
1319       * Boot the threading subsystem.
1320       */
1321      @Interruptible
1322      // except not really, since we don't enable yieldpoints yet
1323      public static void boot() {
1324        outOfMemoryError = new OutOfMemoryError();
1325        dumpLock = new Monitor();
1326        acctLock = new NoYieldpointsMonitor();
1327        debugLock = new NoYieldpointsMonitor();
1328        outputLock = new NoYieldpointsMonitor();
1329        softHandshakeDataLock = new Monitor();
1330        handshakeLock = new Monitor();
1331        doProfileReport = new Latch(false);
1332        monitorBySlot[getCurrentThread().threadSlot] = new NoYieldpointsMonitor();
1333        communicationLockBySlot[getCurrentThread().threadSlot] = new Monitor();
1334        sysCall.sysCreateThreadSpecificDataKeys();
1335        sysCall.sysStashVMThread(getCurrentThread());
1336    
1337        if (traceAcct) {
1338          VM.sysWriteln("boot thread at ",Magic.objectAsAddress(getCurrentThread()));
1339        }
1340    
1341        bindIfRequested();
1342    
1343        threadingInitialized = true;
1344        // Always run timer thread, so we can respond to debug requests
1345        new TimerThread().start();
1346        if (VM.BuildForAdaptiveSystem) {
1347          ObjectHolder.boot();
1348        }
1349    
1350        FinalizerThread.boot();
1351        getCurrentThread().enableYieldpoints();
1352        if (traceAcct) VM.sysWriteln("RVMThread booted");
1353      }
1354    
1355      /**
1356       * Add this thread to the termination watchlist. Called by terminating threads
1357       * before they finish terminating.
1358       */
1359      private void addAboutToTerminate() {
1360        monitor().lockNoHandshake();
1361        isAboutToTerminate = true;
1362        activeMutatorContext = false;
1363        monitor().broadcast();
1364    
1365        handleHandshakeRequest();
1366        deinitMutator();
1367    
1368        // WARNING! DANGER! Since we've set isAboutToTerminate to true, when we
1369        // release this lock the GC will:
1370        // 1) No longer scan the thread's stack (though it will *see* the
1371        // thread's stack and mark the stack itself as live, without scanning
1372        // it).
1373        // 2) No longer include the thread in any mutator phases ... hence the
1374        // need to ensure that the mutator context is flushed above.
1375        // 3) No longer attempt to block the thread.
1376        // Moreover, we can no longer do anything that leads to write barriers
1377        // or allocation.
1378        monitor().unlock();
1379    
1380        softRendezvous();
1381    
1382        acctLock.lockNoHandshake();
1383        aboutToTerminate[aboutToTerminateN++] = threadSlot;
1384        acctLock.unlock();
1385      }
1386    
1387      /**
1388       * Method called after processing a list of threads, or before starting a new
1389       * thread.  This does two things.  First, it guarantees that the thread slots
1390       * used by any dead threads are freed.  Second, it guarantees that each thread
1391       * deregisters itself from GC.  Thus, it is essential that after requesting
1392       * things like mutator flushes, you call this, to ensure that any threads that
1393       * had died before or during the mutator flush request do the Right Thing.
1394       */
1395      @NoCheckStore
1396      public static void processAboutToTerminate() {
1397        if (!neverKillThreads) {
1398          restart: while(true) {
1399            int notKilled = 0;
1400            acctLock.lockNoHandshake();
1401            for (int i = 0; i < aboutToTerminateN; ++i) {
1402              RVMThread t = threadBySlot[aboutToTerminate[i]];
1403              if (t.getExecStatus() == TERMINATED) {
1404                aboutToTerminate[i--] = aboutToTerminate[--aboutToTerminateN];
1405                acctLock.unlock();
1406                t.releaseThreadSlot();
1407                continue restart;
1408              } else {
1409                notKilled++;
1410              }
1411            }
1412            acctLock.unlock();
1413            if (notKilled > 0 && traceAboutToTerminate) {
1414              VM.sysWriteln("didn't kill ", notKilled, " threads");
1415            }
1416            break;
1417          }
1418        }
1419      }
1420    
1421      /**
1422       * Find a thread slot not in use by any other live thread and bind the given
1423       * thread to it. The thread's threadSlot field is set accordingly.
1424       */
1425      @Interruptible
1426      void assignThreadSlot() {
1427        if (!VM.runningVM) {
1428          // primordial thread
1429          threadSlot = 1;
1430          threadBySlot[1] = this;
1431          threads[0] = this;
1432          threadIdx = 0;
1433          numThreads = 1;
1434        } else {
1435          processAboutToTerminate();
1436          acctLock.lockNoHandshake();
1437          if (freeSlotN > 0) {
1438            threadSlot = freeSlots[--freeSlotN];
1439          } else {
1440            if (nextSlot == threads.length) {
1441              VM.sysFail("too many threads");
1442            }
1443            threadSlot = nextSlot++;
1444          }
1445          acctLock.unlock();
1446          // before we actually use this slot, ensure that there is a monitor
1447          // for it. note that if the slot doesn't have a monitor, then we
1448          // "own" it since we allocated it above but haven't done anything
1449          // with it (it's not assigned to a thread, so nobody else can touch
1450          // it)
1451          if (monitorBySlot[threadSlot] == null) {
1452            monitorBySlot[threadSlot] = new NoYieldpointsMonitor();
1453          }
1454          if (communicationLockBySlot[threadSlot] == null) {
1455            Monitor m = new Monitor();
1456            handshakeLock.lockWithHandshake();
1457            communicationLockBySlot[threadSlot] = m;
1458            handshakeLock.unlock();
1459          }
1460          Magic.sync(); /*
1461                         * make sure that nobody sees the thread in any of the
1462                         * tables until the thread slot is inited
1463                         */
1464    
1465          acctLock.lockNoHandshake();
1466          threadBySlot[threadSlot] = this;
1467    
1468          threadIdx = numThreads++;
1469          threads[threadIdx] = this;
1470    
1471          acctLock.unlock();
1472        }
1473        lockingId = threadSlot << ThinLockConstants.TL_THREAD_ID_SHIFT;
1474        if (traceAcct) {
1475          VM.sysWriteln("Thread #", threadSlot, " at ", Magic.objectAsAddress(this));
1476          VM.sysWriteln("stack at ", Magic.objectAsAddress(stack), " up to ", Magic.objectAsAddress(stack).plus(stack.length));
1477        }
1478      }
1479    
1480      /**
1481       * Release a thread's slot in the threads array.
1482       */
1483      @NoCheckStore
1484      void releaseThreadSlot() {
1485        acctLock.lockNoHandshake();
1486        RVMThread replacementThread = threads[numThreads - 1];
1487        threads[threadIdx] = replacementThread;
1488        replacementThread.threadIdx = threadIdx;
1489        threadIdx = -1;
1490        Magic.sync(); /*
1491                       * make sure that if someone is processing the threads array
1492                       * without holding the acctLock (which is definitely legal)
1493                       * then they see the replacementThread moved to the new index
1494                       * before they see the numThreads decremented (otherwise they
1495                       * would miss replacementThread; but with the current
1496                       * arrangement at worst they will see it twice)
1497                       */
1498        threads[--numThreads] = null;
1499        threadBySlot[threadSlot] = null;
1500        freeSlots[freeSlotN++] = threadSlot;
1501        acctLock.unlock();
1502      }
1503    
1504       /**
1505        * Create a new RVM Thread
1506        *
1507        * @param stack The stack on which to execute the thread.
1508        * @param thread The corresponding java.lang.Thread.
1509        * @param name The name of the thread
1510        * @param daemon True if this is a daemon thread.
1511        * @param systemThread True if this is a system thread.
1512        * @param priority The threads execution priority.
1513        */
1514       public RVMThread(byte[] stack, Thread thread, String name, boolean daemon, SystemThread systemThread, int priority) {
1515        this.stack = stack;
1516    
1517        this.daemon = daemon;
1518        this.priority = priority;
1519        this.systemThread = systemThread;
1520    
1521        this.contextRegisters = this.contextRegistersShadow = new Registers();
1522        this.contextRegistersSave = this.contextRegistersSaveShadow = new Registers();
1523        this.exceptionRegisters = this.exceptionRegistersShadow = new Registers();
1524    
1525        if (VM.runningVM) {
1526          feedlet = TraceEngine.engine.makeFeedlet(name, name);
1527        }
1528    
1529        if (VM.VerifyAssertions) VM._assert(stack != null);
1530    
1531        // put self in list of threads known to scheduler and garbage collector
1532        if (!VM.runningVM) {
1533          if (VM.VerifyAssertions) VM._assert(name != null);
1534          this.name = name;
1535          // create primordial thread (in boot image)
1536          assignThreadSlot();
1537    
1538          if (trace)
1539            trace("RVMThread create: ", name);
1540          if (trace)
1541            trace("daemon: ", daemon ? "true" : "false");
1542          if (trace)
1543            trace("RVMThread", "create");
1544    
1545          initMutator(threadSlot);
1546          this.activeMutatorContext = true;
1547          // Remember the boot thread
1548          this.execStatus = IN_JAVA;
1549          this.waiting = Waiting.RUNNABLE;
1550          // assign final field
1551          onStackReplacementEvent = null;
1552        } else {
1553          // create a normal (ie. non-primordial) thread
1554    
1555          // set up wrapper Thread if one exists
1556          this.thread = thread;
1557          // Set thread type
1558    
1559          this.execStatus = NEW;
1560          this.waiting = Waiting.RUNNABLE;
1561    
1562          stackLimit = Magic.objectAsAddress(stack).plus(STACK_SIZE_GUARD);
1563    
1564          // get instructions for method to be executed as thread startoff
1565          CodeArray instructions = Entrypoints.threadStartoffMethod.getCurrentEntryCodeArray();
1566    
1567          VM.disableGC();
1568    
1569          // initialize thread registers
1570          Address ip = Magic.objectAsAddress(instructions);
1571          Address sp = Magic.objectAsAddress(stack).plus(stack.length);
1572    
1573          // Initialize the a thread stack as if "startoff" method had been called
1574          // by an empty baseline-compiled "sentinel" frame with one local variable.
1575          Configuration.archHelper.initializeStack(contextRegisters, ip, sp);
1576    
1577          VM.enableGC();
1578    
1579          assignThreadSlot();
1580          this.name = name == null ? "Thread-" + threadSlot : name;
1581          initMutator(threadSlot);
1582          activeMutatorContext = true;
1583          if (traceAcct) {
1584            VM.sysWriteln("registered mutator for ", threadSlot);
1585          }
1586    
1587          initializeJNIEnv();
1588    
1589          if (VM.BuildForAdaptiveSystem) {
1590            onStackReplacementEvent = new OnStackReplacementEvent();
1591          } else {
1592            onStackReplacementEvent = null;
1593          }
1594    
1595          if (thread == null) {
1596            // create wrapper Thread if doesn't exist
1597            this.thread = java.lang.JikesRVMSupport.createThread(this, name);
1598          }
1599        }
1600      }
1601    
1602      /**
1603       * Create a thread with default stack and with the given name.
1604       */
1605      public RVMThread(SystemThread systemThread, String name) {
1606        this(MemoryManager.newStack(STACK_SIZE_NORMAL), null, // java.lang.Thread
1607            name, true, // daemon
1608            systemThread,
1609            Thread.NORM_PRIORITY);
1610      }
1611    
1612      /**
1613       * Create a thread with the given stack and name. Used by
1614       * {@link org.jikesrvm.mm.mminterface.CollectorThread} and the
1615       * boot image writer for the boot thread.
1616       */
1617      public RVMThread(SystemThread systemThread, byte[] stack, String name) {
1618        this(stack, null, // java.lang.Thread
1619            name, true, // daemon
1620            systemThread,
1621            Thread.NORM_PRIORITY);
1622      }
1623    
1624      /**
1625       * Create a thread with ... called by java.lang.VMThread.create. System thread
1626       * isn't set.
1627       */
1628      public RVMThread(Thread thread, long stacksize, String name, boolean daemon, int priority) {
1629        this(MemoryManager.newStack((stacksize <= 0) ? STACK_SIZE_NORMAL : (int) stacksize), thread, name, daemon, null, priority);
1630      }
1631    
1632      /**
1633       * Check if the thread has block requests (for example, for suspension and GC).  If
1634       * it does, clear the requests and marked the thread as blocked for that request.
1635       * If there were any block requests, do a broadcast() on the thread's monitor().
1636       * This is an internal method and should only be called from code that implements
1637       * thread blocking.  The monitor() lock must be held for this method to work properly.
1638       */
1639      private void acknowledgeBlockRequests() {
1640        boolean hadSome = false;
1641        if (VM.VerifyAssertions)
1642          VM._assert(blockAdapters != null);
1643        for (int i = 0; i < blockAdapters.length; ++i) {
1644          if (blockAdapters[i].hasBlockRequest(this)) {
1645            blockAdapters[i].setBlocked(this, true);
1646            blockAdapters[i].clearBlockRequest(this);
1647            hadSome = true;
1648          }
1649        }
1650        if (hadSome) {
1651          monitor().broadcast();
1652        }
1653      }
1654    
1655      /**
1656       * Checks if the thread system has acknowledged that the thread is supposed
1657       * to be blocked. This will return true if the thread is actually blocking, or
1658       * if the thread is running native code but is guaranteed to block before
1659       * returning to Java.  Only call this method when already holding the monitor(),
1660       * for two reasons:
1661       * <ol>
1662       * <li>This method does not acquire the monitor() lock even though it needs
1663       * to have it acquired given the data structures that it is accessing.
1664       * <li>You will typically want to call this method to decide if you need to
1665       * take action under the assumption that the thread is blocked (or not
1666       * blocked). So long as you hold the lock the thread cannot change state from
1667       * blocked to not blocked.
1668       * </ol>
1669       *
1670       * @return if the thread is supposed to be blocked
1671       */
1672      public boolean isBlocked() {
1673        for (int i = 0; i < blockAdapters.length; ++i) {
1674          if (blockAdapters[i].isBlocked(this)) {
1675            return true;
1676          }
1677        }
1678        return false;
1679      }
1680    
1681      /**
1682       * Checks if the thread is executing Java code. A thread is executing Java
1683       * code if its <code>execStatus</code> is <code>IN_JAVA</code> or
1684       * <code>IN_JAVA_TO_BLOCK</code>, and if it is not
1685       * <code>aboutToTerminate</code>, and if it is not blocked. Only call this
1686       * method when already holding the monitor(), and probably only after calling
1687       * setBlockedExecStatus(), for two reasons:
1688       * <ol>
1689       * <li>This method does not acquire the monitor() lock even though it needs
1690       * to have it acquired given the data structures that it is accessing.
1691       * <li>You will typically want to call this method to decide if you need to
1692       * take action under the assumption that the thread is running Java (or not
1693       * running Java). So long as you hold the lock - and you have called
1694       * setBlockedExecStatus() - the thread cannot change state from running-Java
1695       * to not-running-Java.
1696       * </ol>
1697       *
1698       * @return if the thread is running Java
1699       */
1700      public boolean isInJava() {
1701        return !isBlocking && !isAboutToTerminate &&
1702          (getExecStatus() == IN_JAVA || getExecStatus() == IN_JAVA_TO_BLOCK);
1703      }
1704    
1705      /**
1706       * Should the thread by eligible for sampling by the timer thread?
1707       * Heuristically, we use timer-based sampling the in the adaptive system
1708       * to determine where the program is spending time (and thus what to optimize).
1709       * This doesn't have to be a 100% accurate, but it must be non-blocking
1710       * and also closely approximate whether or not the thread is executing.
1711       * For now, approximate just as being in JAVA.
1712       * As a future item, we may want to actually correctly attribute time
1713       * spent in native code to the top native method on the frame when the timer
1714       * goes off.  This will require work in the JNI enter/exit sequence to deal with
1715       * timer samples appropriately.
1716       */
1717      public boolean shouldBeSampled() {
1718        return execStatus == IN_JAVA;
1719      }
1720    
1721      /** A variant of checkBlock() that does not save the thread state. */
1722      @NoInline
1723      @Unpreemptible("May block if the thread was asked to do so, but otherwise does no actions that would cause blocking")
1724      private void checkBlockNoSaveContext() {
1725        assertUnacceptableStates(NEW, TERMINATED);
1726        if (VM.VerifyAssertions) VM._assert(!isAboutToTerminate);
1727        if (VM.VerifyAssertions) VM._assert(!isBlocking);
1728    
1729        if (traceBlock)
1730          VM.sysWriteln("Thread #", threadSlot, " in checkBlockNoSaveContext");
1731        // NB: anything this method calls CANNOT change the contextRegisters
1732        // or the JNI env. as well, this code will be running concurrently
1733        // with stop-the-world GC!
1734        monitor().lockNoHandshake();
1735        isBlocking = true;
1736        if (traceBlock)
1737          VM.sysWriteln("Thread #", threadSlot,
1738              " acquired lock and has notified everyone that we're blocked");
1739    
1740        // deal with requests that would require a soft handshake rendezvous
1741        handleHandshakeRequest();
1742        // check if a soft handshake has been requested, and if so, clear the
1743        // request
1744        boolean commitSoftRendezvous = softRendezvousCheckAndClear();
1745        if (commitSoftRendezvous) {
1746          // if a soft handshake had been requested, we need to acknowledge it.
1747          // but to acknowledge it we cannot be holding the monitor() lock.
1748          // it turns out that at this point in the code it is perfectly safe
1749          // to release it, because:
1750          // 1) callers of this method expect that it may, in all likelihood,
1751          // release the monitor() lock if they were holding it, since it
1752          // calls wait()
1753          // 2) if the block requests get cleared when we release the lock,
1754          // we won't call wait, since we reacquire the lock prior to checking
1755          // for block requests.
1756          int recCount = monitor().unlockCompletely();
1757          softRendezvousCommit();
1758          monitor().relockNoHandshake(recCount);
1759        }
1760    
1761        if (traceBlock)
1762          VM.sysWriteln("Thread #", threadSlot,
1763                        " has acknowledged soft handshakes");
1764    
1765        boolean hadReallyBlocked=false;
1766    
1767        for (;;) {
1768          // deal with block requests
1769          acknowledgeBlockRequests();
1770          // are we blocked?
1771          if (!isBlocked()) {
1772            break;
1773          }
1774          if (traceReallyBlock) {
1775            hadReallyBlocked=true;
1776            VM.sysWriteln("Thread #", threadSlot,
1777                          " is really blocked with status ", getExecStatus());
1778            VM.sysWriteln("Thread #", threadSlot,
1779                " has fp = ", Magic.getFramePointer());
1780            if (dumpStackOnBlock) {
1781              dumpStack();
1782            }
1783          }
1784          // what if a GC request comes while we're here for a suspend()
1785          // request?
1786          // answer: we get awoken, reloop, and acknowledge the GC block
1787          // request.
1788          monitor().waitNoHandshake();
1789    
1790          if (traceBlock)
1791            VM.sysWriteln("Thread #", threadSlot,
1792                " has awoken; checking if we're still blocked");
1793        }
1794    
1795        if (traceBlock || (traceReallyBlock && hadReallyBlocked))
1796          VM.sysWriteln("Thread #", threadSlot, " is unblocking");
1797    
1798        // we're about to unblock, so indicate to the world that we're running
1799        // again.
1800        setExecStatus(IN_JAVA);
1801        // let everyone know that we're back to executing code
1802        isBlocking = false;
1803        // deal with requests that came up while we were blocked.
1804        handleHandshakeRequest();
1805        monitor().unlock();
1806    
1807        if (traceBlock)
1808          VM.sysWriteln("Thread #", threadSlot, " is unblocked");
1809      }
1810    
1811      /**
1812       * Check if the thread is supposed to block, and if so, block it. This method
1813       * will ensure that soft handshake requests are acknowledged or else
1814       * inhibited, that any blocking request is handled, that the execution state
1815       * of the thread (<code>execStatus</code>) is set to <code>IN_JAVA</code>
1816       * once all blocking requests are cleared, and that other threads are notified
1817       * that this thread is in the middle of blocking by setting the appropriate
1818       * flag (<code>isBlocking</code>). Note that this thread acquires the
1819       * monitor(), though it may release it completely either by calling wait() or
1820       * by calling unlockCompletely(). Thus, although it isn't generally a problem
1821       * to call this method while holding the monitor() lock, you should only do so
1822       * if the loss of atomicity is acceptable.
1823       * <p>
1824       * Generally, this method should be called from the following four places:
1825       * <ol>
1826       * <li>The block() method, if the thread is requesting to block itself.
1827       * Currently such requests only come when a thread calls suspend(). Doing so
1828       * has unclear semantics (other threads may call resume() too early causing
1829       * the well-known race) but must be supported because it's still part of the
1830       * JDK. Why it's safe: the block() method needs to hold the monitor() for the
1831       * time it takes it to make the block request, but does not need to continue
1832       * to hold it when it calls checkBlock(). Thus, the fact that checkBlock()
1833       * breaks atomicity is not a concern.
1834       * <li>The yieldpoint. One of the purposes of a yieldpoint is to periodically
1835       * check if the current thread should be blocked. This is accomplished by
1836       * calling checkBlock(). Why it's safe: the yieldpoint performs several
1837       * distinct actions, all of which individually require the monitor() lock -
1838       * but the monitor() lock does not have to be held contiguously. Thus, the
1839       * loss of atomicity from calling checkBlock() is fine.
1840       * <li>The "WithHandshake" methods of HeavyCondLock. These methods allow you to
1841       * block on a mutex or condition variable while notifying the system that you
1842       * are not executing Java code. When these blocking methods return, they check
1843       * if there had been a request to block, and if so, they call checkBlock().
1844       * Why it's safe: This is subtle. Two cases exist. The first case is when a
1845       * WithHandshake method is called on a HeavyCondLock instance that is not a thread
1846       * monitor(). In this case, it does not matter that checkBlock() may acquire
1847       * and then completely release the monitor(), since the user was not holding
1848       * the monitor(). However, this will break if the user is <i>also</i> holding
1849       * the monitor() when calling the WithHandshake method on a different lock. This case
1850       * should never happen because no other locks should ever be acquired when the
1851       * monitor() is held. Additionally: there is the concern that some other locks
1852       * should never be held while attempting to acquire the monitor(); the
1853       * HeavyCondLock ensures that checkBlock() is only called when that lock
1854       * itself is released. The other case is when a WithHandshake method is called on the
1855       * monitor() itself. This should only be done when using <i>your own</i>
1856       * monitor() - that is the monitor() of the thread your are running on. In
1857       * this case, the WithHandshake methods work because: (i) lockWithHandshake() only calls
1858       * checkBlock() on the initial lock entry (not on recursive entry), so
1859       * atomicity is not broken, and (ii) waitWithHandshake() and friends only call
1860       * checkBlock() after wait() returns - at which point it is safe to release
1861       * and reacquire the lock, since there cannot be a race with broadcast() once
1862       * we have committed to not calling wait() again.
1863       * <li>Any code following a potentially-blocking native call. Case (3) above
1864       * is somewhat subsumed in this except that it is special due to the fact that
1865       * it's blocking on VM locks. So, this case refers specifically to JNI. The
1866       * JNI epilogues will call leaveJNIBlocked(), which calls a variant of this
1867       * method.
1868       * </ol>
1869       */
1870      @NoInline
1871      @NoOptCompile
1872      @BaselineSaveLSRegisters
1873      @Unpreemptible("May block if asked to do so, but otherwise does not actions that would block")
1874      void checkBlock() {
1875        saveThreadState();
1876        checkBlockNoSaveContext();
1877      }
1878    
1879      /**
1880       * Internal method for transitioning a thread from IN_JAVA or IN_JAVA_TO_BLOCK to
1881       * either BLOCKED_IN_NATIVE or BLOCKED_IN_JNI, depending on the value of the jni
1882       * parameter.  It is always safe to conservatively call this method when transitioning
1883       * to native code, though it is faster to call either enterNative(),
1884       * enterJNIFromCallIntoNative(), or enterJNIFromJNIFunctionCall().
1885       * <p>
1886       * This method takes care of all bookkeeping and notifications required when a
1887       * a thread that has been requested to block instead decides to run native code.
1888       * Threads enter native code never need to block, since they will not be executing
1889       * any Java code.  However, such threads must ensure that any system services (like
1890       * GC) that are waiting for this thread to stop are notified that the thread has
1891       * instead chosen to exit Java.  As well, any requests to perform a sot handshake
1892       * must be serviced and acknowledged.
1893       */
1894      private void enterNativeBlockedImpl(boolean jni) {
1895        if (traceReallyBlock)
1896          VM.sysWriteln("Thread #", threadSlot, " entering native blocked.");
1897        // NB: anything this method calls CANNOT change the contextRegisters
1898        // or the JNI env. as well, this code will be running concurrently
1899        // with stop-the-world GC!
1900        boolean commitSoftRendezvous;
1901        monitor().lockNoHandshake();
1902        if (jni) {
1903          jniEnteredBlocked++;
1904          setExecStatus(BLOCKED_IN_JNI);
1905        } else {
1906          nativeEnteredBlocked++;
1907          setExecStatus(BLOCKED_IN_NATIVE);
1908        }
1909        acknowledgeBlockRequests();
1910        handleHandshakeRequest();
1911        commitSoftRendezvous = softRendezvousCheckAndClear();
1912        monitor().unlock();
1913        if (traceBlock)
1914          VM.sysWriteln("Thread #", threadSlot,
1915              " done with the locking part of native entry.");
1916        if (commitSoftRendezvous)
1917          softRendezvousCommit();
1918        if (traceBlock)
1919          VM.sysWriteln("Thread #", threadSlot, " done enter native blocked.");
1920      }
1921    
1922      @Unpreemptible("May block if the thread was asked to do so, but otherwise does no actions that would cause blocking")
1923      private void leaveNativeBlockedImpl() {
1924        checkBlockNoSaveContext();
1925      }
1926    
1927      private void enterNativeBlocked() {
1928        assertAcceptableStates(IN_JAVA,IN_JAVA_TO_BLOCK);
1929        enterNativeBlockedImpl(false);
1930        assertAcceptableStates(IN_NATIVE,BLOCKED_IN_NATIVE);
1931      }
1932    
1933      @Unpreemptible("May block if the thread was asked to do so, but otherwise does no actions that would cause blocking")
1934      private void leaveNativeBlocked() {
1935        assertAcceptableStates(IN_NATIVE,BLOCKED_IN_NATIVE);
1936        leaveNativeBlockedImpl();
1937        assertAcceptableStates(IN_JAVA,IN_JAVA_TO_BLOCK);
1938      }
1939    
1940      private void enterJNIBlocked() {
1941        assertAcceptableStates(IN_JAVA,IN_JAVA_TO_BLOCK);
1942        enterNativeBlockedImpl(true);
1943        assertAcceptableStates(IN_JNI,BLOCKED_IN_JNI);
1944      }
1945    
1946      @Unpreemptible("May block if the thread was asked to do so, but otherwise does no actions that would cause blocking")
1947      private void leaveJNIBlocked() {
1948        assertAcceptableStates(IN_JNI,BLOCKED_IN_JNI);
1949        leaveNativeBlockedImpl();
1950        assertAcceptableStates(IN_JAVA,IN_JAVA_TO_BLOCK);
1951      }
1952    
1953      @Entrypoint
1954      public static void enterJNIBlockedFromJNIFunctionCall() {
1955        RVMThread t=getCurrentThread();
1956        if (traceReallyBlock) {
1957          VM.sysWriteln("Thread #",t.getThreadSlot(), " in enterJNIBlockedFromJNIFunctionCall");
1958          VM.sysWriteln("thread address = ",Magic.objectAsAddress(t));
1959        }
1960        t.enterJNIBlocked();
1961      }
1962    
1963      @Entrypoint
1964      public static void enterJNIBlockedFromCallIntoNative() {
1965        RVMThread t=getCurrentThread();
1966        if (traceReallyBlock) {
1967          VM.sysWriteln("Thread #",t.getThreadSlot(), " in enterJNIBlockedFromCallIntoNative");
1968          VM.sysWriteln("thread address = ",Magic.objectAsAddress(t));
1969        }
1970        t.enterJNIBlocked();
1971      }
1972    
1973      @Entrypoint
1974      @Unpreemptible("May block if the thread was asked to do so, but otherwise will not block")
1975      static void leaveJNIBlockedFromJNIFunctionCall() {
1976        RVMThread t = getCurrentThread();
1977        if (traceReallyBlock) {
1978          VM.sysWriteln("Thread #", t.getThreadSlot(),
1979              " in leaveJNIBlockedFromJNIFunctionCall");
1980          VM.sysWriteln("thread address = ",Magic.objectAsAddress(t));
1981          VM.sysWriteln("state = ", t.getExecStatus());
1982          VM.sysWriteln("jtoc = ", Magic.getJTOC());
1983        }
1984        t.leaveJNIBlocked();
1985      }
1986    
1987      /**
1988       * Called when JNI code tried to transition from  IN_JNI to IN_JAVA but failed
1989       */
1990      @Entrypoint
1991      @Unpreemptible("May block if the thread was asked to do so, but otherwise will not block")
1992      public static void leaveJNIBlockedFromCallIntoNative() {
1993        RVMThread t = getCurrentThread();
1994        if (traceReallyBlock) {
1995          VM.sysWriteln("Thread #", t.getThreadSlot(),
1996              " in leaveJNIBlockedFromCallIntoNative");
1997          VM.sysWriteln("state = ", t.getExecStatus());
1998          VM.sysWriteln("jtoc = ", Magic.getJTOC());
1999        }
2000        t.leaveJNIBlocked();
2001      }
2002    
2003      private int setBlockedExecStatus() {
2004        int oldState, newState;
2005        do {
2006          oldState = getExecStatus();
2007          if (oldState == IN_JAVA) {
2008            newState = IN_JAVA_TO_BLOCK;
2009          } else if (oldState == IN_NATIVE) {
2010            newState = BLOCKED_IN_NATIVE;
2011          } else if (oldState == IN_JNI) {
2012            newState = BLOCKED_IN_JNI;
2013          } else {
2014            newState = oldState;
2015          }
2016          /*
2017           * use the CAS to assert that we observed what we
2018           * thought we observed
2019           */
2020        } while (!(attemptFastExecStatusTransition(oldState,newState)));
2021        return newState;
2022      }
2023    
2024      /**
2025       * Attempt to block the thread, and return the state it is in after the
2026       * attempt. If we're blocking ourselves, this will always return IN_JAVA. If
2027       * the thread signals to us the intention to die as we are trying to block it,
2028       * this will return TERMINATED. NOTE: the thread's execStatus will not
2029       * actually be TERMINATED at that point yet.
2030       * <p>
2031       * Note that this method is ridiculously dangerous, especially if you pass
2032       * asynchronous==false.  Waiting for another thread to stop is not in itself
2033       * interruptible - so if you ask another thread to block and they ask you
2034       * to block, you might deadlock.
2035       */
2036      @Unpreemptible("Only blocks if the receiver is the current thread, or if asynchronous is set to false and the thread is not already blocked")
2037      int block(BlockAdapter ba, boolean asynchronous) {
2038        int result;
2039        if (traceBlock)
2040          VM.sysWriteln("Thread #", getCurrentThread().threadSlot,
2041              " is requesting that thread #", threadSlot, " blocks.");
2042        monitor().lockNoHandshake();
2043        int token = ba.requestBlock(this);
2044        if (getCurrentThread() == this) {
2045          if (traceBlock)
2046            VM.sysWriteln("Thread #", threadSlot, " is blocking.");
2047          checkBlock();
2048          result = getExecStatus();
2049        } else {
2050          if (traceBlock)
2051            VM.sysWriteln("Thread #", threadSlot, " is being told to block.");
2052          if (isAboutToTerminate) {
2053            if (traceBlock)
2054              VM.sysWriteln("Thread #", threadSlot,
2055                  " is terminating, returning as if blocked in TERMINATED state.");
2056            result = TERMINATED;
2057          } else {
2058            takeYieldpoint = 1;
2059            // CAS the execStatus field
2060            int newState = setBlockedExecStatus();
2061            result = newState;
2062            if (traceReallyBlock)
2063              VM.sysWriteln("Thread #", getCurrentThreadSlot(),
2064                  " is blocking thread #", threadSlot, " which is in state ",
2065                  newState);
2066            // this broadcast serves two purposes: notifies threads that are
2067            // IN_JAVA but waiting on monitor() that they should awake and
2068            // acknowledge the block request; or notifies anyone
2069            // waiting for this thread to block that the thread is
2070            // BLOCKED_IN_NATIVE or BLOCKED_IN_JNI. in the latter case the
2071            // broadcast() happens _before_ the setting of the flags that the
2072            // other threads would be awaiting, but that is fine, since we're
2073            // still holding the lock anyway.
2074            monitor().broadcast();
2075            if (newState == IN_JAVA_TO_BLOCK) {
2076              if (!asynchronous) {
2077                if (traceBlock)
2078                  VM.sysWriteln("Thread #", getCurrentThread().threadSlot,
2079                      " is waiting for thread #", threadSlot, " to block.");
2080                while (ba.hasBlockRequest(this, token) && !ba.isBlocked(this) && !isAboutToTerminate) {
2081                  if (traceBlock)
2082                    VM.sysWriteln("Thread #", getCurrentThread().threadSlot,
2083                        " is calling wait until thread #", threadSlot, " blocks.");
2084                  // will this deadlock when the thread dies?
2085                  if (VM.VerifyAssertions) {
2086                    // do a timed wait, and assert that the thread did not disappear
2087                    // into native in the meantime
2088                    monitor().timedWaitRelativeNoHandshake(1000L * 1000L * 1000L); // 1 sec
2089                    if (traceReallyBlock) {
2090                      VM.sysWriteln("Thread #", threadSlot, "'s status is ",
2091                                    getExecStatus());
2092                    }
2093                    assertUnacceptableStates(IN_NATIVE);
2094                  } else {
2095                    monitor().waitNoHandshake();
2096                  }
2097                  if (traceBlock)
2098                    VM.sysWriteln("Thread #", getCurrentThread().threadSlot,
2099                        " has returned from the wait call.");
2100                }
2101                if (isAboutToTerminate) {
2102                  result = TERMINATED;
2103                } else {
2104                  result=getExecStatus();
2105                }
2106              }
2107            } else if (newState == BLOCKED_IN_NATIVE || newState == BLOCKED_IN_JNI) {
2108              // we own the thread for now - it cannot go back to executing Java
2109              // code until we release the lock. before we do so we change its
2110              // state accordingly and tell anyone who is waiting.
2111              if (traceBlock)
2112                VM.sysWriteln("Thread #", getCurrentThread().threadSlot,
2113                    " has seen thread #", threadSlot,
2114                    " in native; changing its status accordingly.");
2115              ba.clearBlockRequest(this);
2116              ba.setBlocked(this, true);
2117            }
2118          }
2119        }
2120        monitor().unlock();
2121        if (traceReallyBlock)
2122          VM.sysWriteln("Thread #", getCurrentThread().threadSlot,
2123              " is done telling thread #", threadSlot, " to block.");
2124        return result;
2125      }
2126    
2127      public boolean blockedFor(BlockAdapter ba) {
2128        monitor().lockNoHandshake();
2129        boolean result = ba.isBlocked(this);
2130        monitor().unlock();
2131        return result;
2132      }
2133    
2134      @UninterruptibleNoWarn("Never blocks; only asynchronously notifies the receiver to do so")
2135      public int asyncBlock(BlockAdapter ba) {
2136        if (VM.VerifyAssertions)
2137          VM._assert(getCurrentThread() != this);
2138        return block(ba, true);
2139      }
2140    
2141      @Unpreemptible("May block if the receiver is the current thread or if the receiver is not yet blocked; otherwise does not perform actions that lead to blocking")
2142      public int block(BlockAdapter ba) {
2143        return block(ba, false);
2144      }
2145    
2146      @Unpreemptible
2147      public void beginPairWith(RVMThread other) {
2148        if (traceBlock) VM.sysWriteln("attempting to pair ",threadSlot," with ",other.threadSlot);
2149        Monitor.lockWithHandshake(
2150          communicationLock(),Word.fromIntSignExtend(threadSlot),
2151          other.communicationLock(),Word.fromIntSignExtend(other.threadSlot));
2152      }
2153    
2154      public void endPairWith(RVMThread other) {
2155        communicationLock().unlock();
2156        other.communicationLock().unlock();
2157        if (traceBlock) VM.sysWriteln("unpairing ",threadSlot," from ",other.threadSlot);
2158      }
2159    
2160      @Unpreemptible
2161      public void beginPairWithCurrent() {
2162        beginPairWith(getCurrentThread());
2163      }
2164    
2165      public void endPairWithCurrent() {
2166        endPairWith(getCurrentThread());
2167      }
2168    
2169      @Unpreemptible
2170      private int safeBlock(BlockAdapter ba, boolean asynchronous) {
2171        if (VM.VerifyAssertions)
2172          VM._assert(getCurrentThread() != this);
2173        beginPairWithCurrent();
2174        int result=block(ba,asynchronous);
2175        endPairWithCurrent();
2176        return result;
2177      }
2178    
2179      @Unpreemptible
2180      public int safeAsyncBlock(BlockAdapter ba) {
2181        return safeBlock(ba, true);
2182      }
2183    
2184      @Unpreemptible
2185      public int safeBlock(BlockAdapter ba) {
2186        if (getCurrentThread()==this) {
2187          return block(ba,false);
2188        } else {
2189          return safeBlock(ba, false);
2190        }
2191      }
2192    
2193      @Unpreemptible
2194      public void beginPairHandshake() {
2195        beginPairWithCurrent();
2196        block(handshakeBlockAdapter);
2197      }
2198    
2199      @Uninterruptible
2200      public void endPairHandshake() {
2201        unblock(handshakeBlockAdapter);
2202        endPairWithCurrent();
2203      }
2204    
2205      /**
2206       * Save the current thread state.  Call this prior to calling enterNative().  You must
2207       * be in a method that is marked BaselineSaveLSRegisters.
2208       */
2209      @NoInline
2210      public static void saveThreadState() {
2211        Address curFP=Magic.getFramePointer();
2212        getCurrentThread().contextRegisters.setInnermost(Magic.getReturnAddressUnchecked(curFP),
2213                                                         Magic.getCallerFramePointer(curFP));
2214      }
2215    
2216      /**
2217       * Indicate that we'd like the current thread to be executing privileged code that
2218       * does not require synchronization with the GC.  This call may be made on a thread
2219       * that is IN_JAVA or IN_JAVA_TO_BLOCK, and will result in the thread being either
2220       * IN_NATIVE or BLOCKED_IN_NATIVE.  In the case of an
2221       * IN_JAVA_TO_BLOCK-&gt;BLOCKED_IN_NATIVE transition, this call will acquire the
2222       * thread's lock and send out a notification to any threads waiting for this thread
2223       * to reach a safepoint.  This notification serves to notify them that the thread
2224       * is in GC-safe code, but will not reach an actual safepoint for an indetermined
2225       * amount of time.  This is significant, because safepoints may perform additional
2226       * actions (such as handling handshake requests, which may include things like
2227       * mutator flushes and running isync) that IN_NATIVE code will not perform until
2228       * returning to IN_JAVA by way of a leaveNative() call.
2229       */
2230      @NoInline // so we can get the fp
2231      public static void enterNative() {
2232        RVMThread t = getCurrentThread();
2233        if (ALWAYS_LOCK_ON_STATE_TRANSITION) {
2234          t.enterNativeBlocked();
2235        } else {
2236          int oldState, newState;
2237          do {
2238            oldState = t.getExecStatus();
2239            if (oldState == IN_JAVA) {
2240              newState = IN_NATIVE;
2241            } else {
2242              t.assertAcceptableStates(IN_JAVA_TO_BLOCK);
2243              t.enterNativeBlocked();
2244              return;
2245            }
2246          } while (!(t.attemptFastExecStatusTransition(oldState, newState)));
2247        }
2248        // NB this is not a correct assertion, as there is a race.  we could succeed in
2249        // CASing the status to IN_NATIVE, but then someone else could asynchronosly
2250        // set it to whatever they want.
2251        //if (VM.VerifyAssertions)
2252        //  VM._assert(t.execStatus == IN_NATIVE);
2253      }
2254    
2255      /**
2256       * Attempt to transition from IN_JNI or IN_NATIVE to IN_JAVA, fail if execStatus is
2257       * anything but IN_JNI or IN_NATIVE.
2258       *
2259       * @return true if thread transitioned to IN_JAVA, otherwise false
2260       */
2261      public static boolean attemptLeaveNativeNoBlock() {
2262        if (ALWAYS_LOCK_ON_STATE_TRANSITION)
2263          return false;
2264        RVMThread t = getCurrentThread();
2265        int oldState, newState;
2266        do {
2267          oldState = t.getExecStatus();
2268          if (oldState == IN_NATIVE || oldState == IN_JNI) {
2269            newState = IN_JAVA;
2270          } else {
2271            t.assertAcceptableStates(BLOCKED_IN_NATIVE,BLOCKED_IN_JNI);
2272            return false;
2273          }
2274        } while (!(t.attemptFastExecStatusTransition(oldState, newState)));
2275        return true;
2276      }
2277    
2278      /**
2279       * Leave privileged code.  This is valid for threads that are either IN_NATIVE,
2280       * IN_JNI, BLOCKED_IN_NATIVE, or BLOCKED_IN_JNI, and always results in the thread
2281       * being IN_JAVA.  If the thread was previously BLOCKED_IN_NATIVE or BLOCKED_IN_JNI,
2282       * the thread will block until notified that it can run again.
2283       */
2284      @Unpreemptible("May block if the thread was asked to do so; otherwise does no actions that would lead to blocking")
2285      public static void leaveNative() {
2286        if (!attemptLeaveNativeNoBlock()) {
2287          if (traceReallyBlock) {
2288            VM.sysWriteln("Thread #", getCurrentThreadSlot(),
2289                " is leaving native blocked");
2290          }
2291          getCurrentThread().leaveNativeBlocked();
2292        }
2293      }
2294    
2295      public static void enterJNIFromCallIntoNative() {
2296        // FIXME: call these in PPC instead of doing it in machine code...
2297        getCurrentThread().observeExecStatus();
2298        if (!getCurrentThread().attemptFastExecStatusTransition(RVMThread.IN_JAVA,
2299            RVMThread.IN_JNI)) {
2300          RVMThread.enterJNIBlockedFromCallIntoNative();
2301        }
2302      }
2303    
2304      @Unpreemptible
2305      public static void leaveJNIFromCallIntoNative() {
2306        // FIXME: call these in PPC instead of doing it in machine code...
2307        getCurrentThread().observeExecStatus();
2308        if (!getCurrentThread().attemptFastExecStatusTransition(RVMThread.IN_JNI,
2309            RVMThread.IN_JAVA)) {
2310          RVMThread.leaveJNIBlockedFromCallIntoNative();
2311        }
2312      }
2313    
2314      public static void enterJNIFromJNIFunctionCall() {
2315        // FIXME: call these instead of doing it in machine code...  currently this
2316        // is never called.
2317        getCurrentThread().observeExecStatus();
2318        if (!getCurrentThread().attemptFastExecStatusTransition(RVMThread.IN_JAVA,
2319            RVMThread.IN_JNI)) {
2320          RVMThread.enterJNIBlockedFromJNIFunctionCall();
2321        }
2322      }
2323    
2324      @Unpreemptible
2325      public static void leaveJNIFromJNIFunctionCall() {
2326        // FIXME: call these instead of doing it in machine code...  currently this
2327        // is never called.
2328        getCurrentThread().observeExecStatus();
2329        if (!getCurrentThread().attemptFastExecStatusTransition(RVMThread.IN_JNI,
2330            RVMThread.IN_JAVA)) {
2331          RVMThread.leaveJNIBlockedFromJNIFunctionCall();
2332        }
2333      }
2334    
2335      public void unblock(BlockAdapter ba) {
2336        if (traceBlock)
2337          VM.sysWriteln("Thread #", getCurrentThread().threadSlot,
2338              " is requesting that thread #", threadSlot, " unblocks.");
2339        monitor().lockNoHandshake();
2340        ba.clearBlockRequest(this);
2341        ba.setBlocked(this, false);
2342        monitor().broadcast();
2343        monitor().unlock();
2344        if (traceBlock)
2345          VM.sysWriteln("Thread #", getCurrentThread().threadSlot,
2346              " is done requesting that thread #", threadSlot, " unblocks.");
2347      }
2348    
2349      private void handleDebugRequestForThread() {
2350        monitor().lockNoHandshake();
2351        dumpLock.lockNoHandshake();
2352        extDump();
2353        if (!isAboutToTerminate) {
2354          setBlockedExecStatus();
2355          if (isInJava()) {
2356            asyncDebugRequestedForThisThread = true;
2357            takeYieldpoint = 1;
2358            VM.sysWriteln("(stack trace will follow if thread is not lost...)");
2359          } else {
2360            if (contextRegisters != null) {
2361              dumpStack(contextRegisters.getInnermostFramePointer());
2362            } else {
2363              VM.sysWriteln("(cannot dump stack trace; thread is not running in Java but has no contextRegisters)");
2364            }
2365          }
2366        }
2367        dumpLock.unlock();
2368        monitor().unlock();
2369      }
2370    
2371      @NoCheckStore
2372      public static void checkDebugRequest() {
2373        if (debugRequested) {
2374          debugLock.lockNoHandshake();
2375          if (debugRequested) {
2376            debugRequested = false;
2377            VM.sysWriteln("=== Debug requested - attempting safe VM dump ===");
2378            dumpAcct();
2379            reportThreadTransitionCounts();
2380    
2381            // FIXME: this code runs concurrently to GC and has no way of stopping
2382            // it.  hence it is dangerous.  leaving it as-is for now, since it's
2383            // only meant to be used for debugging.
2384    
2385            VM.sysWriteln("Timer ticks = ", timerTicks);
2386            doProfileReport.openNoHandshake();
2387            // snapshot the threads
2388            acctLock.lockNoHandshake();
2389            int numDebugThreads = numThreads;
2390            for (int i = 0; i < numThreads; ++i) {
2391              debugThreads[i] = threads[i];
2392            }
2393            acctLock.unlock();
2394            // do the magic
2395            for (int i = 0; i < numDebugThreads; ++i) {
2396              debugThreads[i].handleDebugRequestForThread();
2397              debugThreads[i] = null;
2398            }
2399          }
2400          debugLock.unlock();
2401        }
2402      }
2403    
2404      void timerTick() {
2405        if (shouldBeSampled()) {
2406          timeSliceExpired++;
2407          takeYieldpoint=1;
2408        }
2409      }
2410    
2411      /** Are we allowed to take yieldpoints? */
2412      @Inline
2413      public boolean yieldpointsEnabled() {
2414        return yieldpointsEnabledCount == 1;
2415      }
2416    
2417      /** Enable yieldpoints on this thread. */
2418      public void enableYieldpoints() {
2419        ++yieldpointsEnabledCount;
2420        if (VM.VerifyAssertions)
2421          VM._assert(yieldpointsEnabledCount <= 1);
2422        if (yieldpointsEnabled() && yieldpointRequestPending) {
2423          takeYieldpoint = 1;
2424          yieldpointRequestPending = false;
2425        }
2426      }
2427    
2428      /** Disable yieldpoints on this thread. */
2429      public void disableYieldpoints() {
2430        --yieldpointsEnabledCount;
2431      }
2432    
2433      /**
2434       * Fail if yieldpoints are disabled on this thread
2435       */
2436      public void failIfYieldpointsDisabled() {
2437        if (!yieldpointsEnabled()) {
2438          VM.sysWrite("No yieldpoints on thread ", threadSlot);
2439          VM.sysWrite(" with addr ", Magic.objectAsAddress(this));
2440          VM.sysWriteln();
2441          VM.sysFail("Yieldpoints are disabled on this thread!");
2442        }
2443      }
2444    
2445      /**
2446       * @return The currently executing thread
2447       */
2448      @Uninterruptible
2449      public static RVMThread getCurrentThread() {
2450        return ThreadLocalState.getCurrentThread();
2451      }
2452    
2453      /**
2454       * @return the unique slot of the currently executing thread
2455       */
2456      public static int getCurrentThreadSlot() {
2457        return getCurrentThread().threadSlot;
2458      }
2459    
2460      /**
2461       * @return the slot of this thread
2462       */
2463      public int getThreadSlot() {
2464        return threadSlot;
2465      }
2466    
2467      /**
2468       * Called during booting to give the boot thread a java.lang.Thread
2469       */
2470      @Interruptible
2471      public void setupBootJavaThread() {
2472        thread = java.lang.JikesRVMSupport.createThread(this,
2473            "Jikes_RVM_Boot_Thread");
2474      }
2475    
2476      /**
2477       * String representation of thread
2478       */
2479      @Override
2480      public String toString() {
2481        return name;
2482      }
2483    
2484      /**
2485       * Get the current java.lang.Thread.
2486       */
2487      public Thread getJavaLangThread() {
2488        return thread;
2489      }
2490    
2491      /**
2492       * Get current thread's JNI environment.
2493       */
2494      public JNIEnvironment getJNIEnv() {
2495        return jniEnv;
2496      }
2497    
2498      /** Get the disable GC depth */
2499      public int getDisableGCDepth() {
2500        return disableGCDepth;
2501      }
2502    
2503      /** Modify the disable GC depth */
2504      public void setDisableGCDepth(int d) {
2505        disableGCDepth = d;
2506      }
2507    
2508      /** Are allocations allowed by this thread? */
2509      public boolean getDisallowAllocationsByThisThread() {
2510        return disallowAllocationsByThisThread;
2511      }
2512    
2513      /** Disallow allocations by this thread */
2514      public void setDisallowAllocationsByThisThread() {
2515        disallowAllocationsByThisThread = true;
2516      }
2517    
2518      /** Allow allocations by this thread */
2519      public void clearDisallowAllocationsByThisThread() {
2520        disallowAllocationsByThisThread = false;
2521      }
2522    
2523      /**
2524       * Initialize JNI environment for system threads. Called by VM.finishBooting
2525       */
2526      @Interruptible
2527      public void initializeJNIEnv() {
2528        this.jniEnv = this.jniEnvShadow = new JNIEnvironment();
2529      }
2530    
2531      /**
2532       * Indicate whether the stack of this Thread contains any C frame (used in
2533       * RuntimeEntrypoints.deliverHardwareException for stack resize)
2534       *
2535       * @return false during the prolog of the first Java to C transition true
2536       *         afterward
2537       */
2538      public boolean hasNativeStackFrame() {
2539        return jniEnv != null && jniEnv.hasNativeStackFrame();
2540      }
2541    
2542      /*
2543       * Starting and ending threads
2544       */
2545    
2546      /**
2547       * Method to be executed when this thread starts running. Calls
2548       * java.lang.Thread.run but system threads can override directly.
2549       */
2550      @Interruptible
2551      @Entrypoint
2552      public void run() {
2553        try {
2554          synchronized (thread) {
2555            Throwable t = java.lang.JikesRVMSupport.getStillBorn(thread);
2556            if (t != null) {
2557              java.lang.JikesRVMSupport.setStillBorn(thread, null);
2558              throw t;
2559            }
2560          }
2561          thread.run();
2562        } catch (Throwable t) {
2563          if (traceAcct) {
2564            VM.sysWriteln("Thread ",getThreadSlot()," exiting with exception.");
2565          }
2566          try {
2567            Thread.UncaughtExceptionHandler handler;
2568            handler = thread.getUncaughtExceptionHandler();
2569            handler.uncaughtException(thread, t);
2570          } catch (Throwable ignore) {
2571          }
2572        }
2573      }
2574    
2575      /**
2576       * Begin execution of current thread by calling its "run" method. This method
2577       * is at the bottom of all created method's stacks.
2578       */
2579      @Interruptible
2580      @SuppressWarnings({ "unused" })
2581      // Called by back-door methods.
2582      private static void startoff() {
2583        bindIfRequested();
2584    
2585        sysCall.sysSetupHardwareTrapHandler();
2586    
2587        RVMThread currentThread = getCurrentThread();
2588    
2589        /*
2590         * get pthread_id from the operating system and store into RVMThread field
2591         */
2592        currentThread.pthread_id = sysCall.sysGetThreadId();
2593        currentThread.enableYieldpoints();
2594        sysCall.sysStashVMThread(currentThread);
2595        if (traceAcct) {
2596          VM.sysWriteln("Thread #", currentThread.threadSlot, " with pthread id ",
2597              currentThread.pthread_id, " running!");
2598        }
2599    
2600        if (trace) {
2601          VM.sysWriteln("Thread.startoff(): about to call ", currentThread.toString(), ".run()");
2602        }
2603    
2604        try {
2605          if (currentThread.systemThread != null) {
2606            currentThread.systemThread.run();
2607          } else {
2608            currentThread.run();
2609          }
2610        } finally {
2611          if (trace) {
2612            VM.sysWriteln("Thread.startoff(): finished ", currentThread.toString(), ".run()");
2613          }
2614          currentThread.terminate();
2615          if (VM.VerifyAssertions)
2616            VM._assert(VM.NOT_REACHED);
2617        }
2618      }
2619    
2620      /**
2621       * Start execution of 'this' by putting it on the appropriate queue of an
2622       * unspecified virtual processor.
2623       */
2624      @Interruptible
2625      public void start() {
2626        // N.B.: cannot hit a yieldpoint between setting execStatus and starting the
2627        // thread!!
2628        setExecStatus(IN_JAVA);
2629        acctLock.lockNoHandshake();
2630        numActiveThreads++;
2631        if (daemon) {
2632          numActiveDaemons++;
2633        }
2634        acctLock.unlock();
2635        if (traceAcct)
2636          VM.sysWriteln("Thread #", threadSlot, " starting!");
2637        sysCall.sysThreadCreate(Magic.objectAsAddress(this),
2638            contextRegisters.ip, contextRegisters.getInnermostFramePointer());
2639      }
2640    
2641      /**
2642       * Terminate execution of current thread by abandoning all references to it
2643       * and resuming execution in some other (ready) thread.
2644       */
2645      @Interruptible
2646      public void terminate() {
2647        if (traceAcct)
2648          VM.sysWriteln("in terminate() for Thread #", threadSlot);
2649        if (VM.VerifyAssertions)
2650          VM._assert(getCurrentThread() == this);
2651        boolean terminateSystem = false;
2652        if (traceTermination) {
2653          VM.disableGC();
2654          VM.sysWriteln("[ BEGIN Verbosely dumping stack at time of thread termination");
2655          dumpStack();
2656          VM.sysWriteln("END Verbosely dumping stack at time of creating thread termination ]");
2657          VM.enableGC();
2658        }
2659    
2660        // allow java.lang.Thread.exit() to remove this thread from ThreadGroup
2661        java.lang.JikesRVMSupport.threadDied(thread);
2662    
2663        TraceEngine.engine.removeFeedlet(feedlet);
2664    
2665        if (VM.VerifyAssertions) {
2666          if (Lock.countLocksHeldByThread(getLockingId()) > 0) {
2667            VM.sysWriteln("Error, thread terminating holding a lock");
2668            RVMThread.dumpVirtualMachine();
2669          }
2670        }
2671    
2672        if (traceAcct)
2673          VM.sysWriteln("doing accounting...");
2674        acctLock.lockNoHandshake();
2675    
2676        // if the thread terminated because of an exception, remove
2677        // the mark from the exception register object, or else the
2678        // garbage collector will attempt to relocate its ip field.
2679        exceptionRegisters.inuse = false;
2680    
2681        numActiveThreads -= 1;
2682        if (daemon) {
2683          numActiveDaemons -= 1;
2684        }
2685        if (traceAcct)
2686          VM.sysWriteln("active = ", numActiveThreads, ", daemons = ",
2687              numActiveDaemons);
2688        if ((numActiveDaemons == numActiveThreads) && (VM.mainThread != null) && VM.mainThread.launched) {
2689          // no non-daemon thread remains and the main thread was launched
2690          terminateSystem = true;
2691        }
2692        if (terminateSystem) {
2693          if (systemShuttingDown == false) {
2694            systemShuttingDown = true;
2695          } else {
2696            terminateSystem = false;
2697          }
2698        }
2699        if (traceTermination) {
2700          VM.sysWriteln("Thread.terminate: myThread.daemon = ", daemon);
2701          VM.sysWriteln("  RVMThread.numActiveThreads = ",
2702              RVMThread.numActiveThreads);
2703          VM.sysWriteln("  RVMThread.numActiveDaemons = ",
2704              RVMThread.numActiveDaemons);
2705          VM.sysWriteln("  terminateSystem = ", terminateSystem);
2706        }
2707    
2708        acctLock.unlock();
2709    
2710        if (traceAcct)
2711          VM.sysWriteln("done with accounting.");
2712    
2713        if (terminateSystem) {
2714          if (traceAcct)
2715            VM.sysWriteln("terminating system.");
2716          if (uncaughtExceptionCount > 0)
2717          /* Use System.exit so that any shutdown hooks are run. */{
2718            if (VM.TraceExceptionDelivery) {
2719              VM.sysWriteln("Calling sysExit due to uncaught exception.");
2720            }
2721            callSystemExit(VM.EXIT_STATUS_DYING_WITH_UNCAUGHT_EXCEPTION);
2722          } else if (thread instanceof MainThread) {
2723            MainThread mt = (MainThread) thread;
2724            if (!mt.launched) {
2725              /*
2726               * Use System.exit so that any shutdown hooks are run. It is possible
2727               * that shutdown hooks may be installed by static initializers which
2728               * were run by classes initialized before we attempted to run the main
2729               * thread. (As of this writing, 24 January 2005, the Classpath
2730               * libraries do not do such a thing, but there is no reason why we
2731               * should not support this.) This was discussed on
2732               * jikesrvm-researchers on 23 Jan 2005 and 24 Jan 2005.
2733               */
2734              callSystemExit(VM.EXIT_STATUS_MAIN_THREAD_COULD_NOT_LAUNCH);
2735            }
2736          }
2737          /* Use System.exit so that any shutdown hooks are run. */
2738          callSystemExit(0);
2739          if (VM.VerifyAssertions)
2740            VM._assert(VM.NOT_REACHED);
2741        }
2742    
2743        if (traceAcct)
2744          VM.sysWriteln("making joinable...");
2745    
2746        // this works.  we use synchronized because we cannot use the thread's
2747        // monitor().  see comment in join().  this is fine, because we're still
2748        // "running" from the standpoint of GC.
2749        synchronized (this) {
2750          isJoinable = true;
2751          notifyAll();
2752        }
2753        if (traceAcct)
2754          VM.sysWriteln("Thread #", threadSlot, " is joinable.");
2755    
2756        if (traceAcct)
2757          VM.sysWriteln("making joinable...");
2758    
2759        // Switch to uninterruptible portion of termination
2760        terminateUnpreemptible();
2761      }
2762    
2763      /**
2764       * Call System.exit() with the correct security status.
2765       *
2766       * @param exitStatus
2767       */
2768      @Interruptible
2769      private void callSystemExit(final int exitStatus) {
2770        AccessController.doPrivileged(new PrivilegedAction<Object>() {
2771          @Override
2772          public Object run() {
2773            System.exit(exitStatus);
2774            return null;
2775          }
2776        });
2777      }
2778    
2779      /**
2780       * Unpreemptible portion of thread termination. Unpreemptible to avoid a dead
2781       * thread from being scheduled.
2782       */
2783      @Unpreemptible
2784      private void terminateUnpreemptible() {
2785        // return cached free lock
2786        if (traceAcct)
2787          VM.sysWriteln("returning cached lock...");
2788    
2789        if (cachedFreeLock != null) {
2790          if (Lock.trace) {
2791            VM.sysWriteln("Thread #", threadSlot, ": about to free lock ",
2792                Magic.objectAsAddress(cachedFreeLock));
2793          }
2794          if (VM.VerifyAssertions)
2795            VM._assert(cachedFreeLock.mutex.latestContender != this);
2796          Lock.returnLock(cachedFreeLock);
2797          cachedFreeLock = null;
2798        }
2799    
2800        if (traceAcct)
2801          VM.sysWriteln("adding to aboutToTerminate...");
2802    
2803        addAboutToTerminate();
2804        // NB we can no longer do anything that would lead to write barriers or
2805        // GC
2806    
2807        if (traceAcct) {
2808          VM.sysWriteln("acquireCount for my monitor: ", monitor().acquireCount);
2809          VM.sysWriteln("timer ticks: ", timerTicks);
2810          VM.sysWriteln("yieldpoints taken: ", yieldpointsTaken);
2811          VM.sysWriteln("yieldpoints taken fully: ", yieldpointsTakenFully);
2812        }
2813        if (traceAcct)
2814          VM.sysWriteln("finishing thread termination...");
2815    
2816        finishThreadTermination();
2817      }
2818    
2819      /** Uninterruptible final portion of thread termination. */
2820      void finishThreadTermination() {
2821        sysCall.sysThreadTerminate();
2822        if (VM.VerifyAssertions)
2823          VM._assert(VM.NOT_REACHED);
2824      }
2825    
2826      /*
2827       * Support for yieldpoints
2828       */
2829    
2830      /**
2831       * Yieldpoint taken in prologue.
2832       */
2833      @BaselineSaveLSRegisters
2834      // Save all non-volatile registers in prologue
2835      @NoOptCompile
2836      @NoInline
2837      // We should also have a pragma that saves all non-volatiles in opt compiler,
2838      // BaselineExecuctionStateExtractor.java, should then restore all
2839      // non-volatiles before stack replacement
2840      // TODO fix this -- related to SaveVolatile
2841      @Entrypoint
2842      @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process")
2843      public static void yieldpointFromPrologue() {
2844        Address fp = Magic.getFramePointer();
2845        yieldpoint(PROLOGUE, fp);
2846      }
2847    
2848      /**
2849       * Yieldpoint taken on backedge.
2850       */
2851      @BaselineSaveLSRegisters
2852      // Save all non-volatile registers in prologue
2853      @NoOptCompile
2854      @NoInline
2855      // We should also have a pragma that saves all non-volatiles in opt compiler,
2856      // BaselineExecuctionStateExtractor.java, should then restore all
2857      // non-volatiles before stack replacement
2858      // TODO fix this -- related to SaveVolatile
2859      @Entrypoint
2860      @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process")
2861      public static void yieldpointFromBackedge() {
2862        Address fp = Magic.getFramePointer();
2863        yieldpoint(BACKEDGE, fp);
2864      }
2865    
2866      /**
2867       * The return barrier.
2868       * <p>
2869       * The following code implements return barriers as described
2870       * for Lisp by Yuasa
2871       *
2872       * http://www.yuasa.kuis.kyoto-u.ac.jp/~yuasa/ilc2002/index.html
2873       * http://dx.doi.org/10.1109/ISORC.2005.45
2874       *
2875       * and for Jikes RVM by Kumar et al
2876       *
2877       * http://dx.doi.org/10.1145/2398857.2384639
2878       * <p>
2879       * This code is executed when a method returns into a frame that
2880       * has been hijacked by the return barrier mechanism.   The return
2881       * barrier trampoline will save state, execute this method, and
2882       * then upon return from this method will transparently return into
2883       * the frame that had been hijacked.
2884       * <p>
2885       * In this default implementation, the barrier reinstalls itself
2886       * in the caller's frame thus incrementally moving the barrier down
2887       * the stack.
2888       * <p>
2889       * The execution of this method is fragile.  It is generally safest
2890       * to call some other method from here that does the substantive work
2891       * of the barrier.
2892       */
2893      @Entrypoint
2894      @Uninterruptible
2895      @Unpreemptible
2896      public static void returnBarrier() {
2897        /* reinstall the barrier in the caller's frame */
2898        if (DEBUG_STACK_TRAMPOLINE) {
2899          VM.sysWriteln(getCurrentThread().getId(), " T0: ", getCurrentThread().trampolineRegisters.gprs.get(BaselineConstants.T0_int).toAddress());
2900          VM.sysWriteln(getCurrentThread().getId(), " T1: ", getCurrentThread().trampolineRegisters.gprs.get(BaselineConstants.T1_int).toAddress());
2901          VM.sysWriteln(getCurrentThread().getId(), " nf: ", getCurrentThread().hijackedReturnCallerFp);
2902          VM.sysWriteln(getCurrentThread().getId(), " lf: ", getCurrentThread().hijackedReturnCalleeFp);
2903          VM.sysWriteln(getCurrentThread().getId(), " fp: ", Magic.getFramePointer());
2904          VM.sysWriteln(getCurrentThread().getId(), " np: ", Magic.getCallerFramePointer(Magic.getFramePointer()));
2905        }
2906        /* reinstall the barrier in the specified frame */
2907        getCurrentThread().installStackTrampolineBridge(getCurrentThread().hijackedReturnCallerFp);
2908      }
2909    
2910      /**
2911       * Install the stack trampoline bridge at a given frame, hijacking
2912       * that frame, saving the hijacked return address and callee fp
2913       * in thread-local state to allow execution of the hijacked frame
2914       * later.
2915       *
2916       * @param targetFp The frame to be hijacked.
2917       */
2918      @Uninterruptible
2919      public void installStackTrampolineBridge(Address targetFp) {
2920        Address trampoline = getStackTrampolineBridgeIP();
2921        if (trampoline.isZero()) {
2922          if (VM.VerifyAssertions)
2923            VM._assert(VM.NOT_REACHED);
2924          else
2925            VM.sysWriteln("Warning: attempt to install stack trampoline without bridge instructions - nothing done.  See RVMThread.");
2926        } else if (trampoline.NE(Magic.getReturnAddressUnchecked(targetFp))) {
2927          /* install the trampoline at fp or the next suitable frame after fp */
2928          while (true) {
2929            if (Magic.getCallerFramePointer(targetFp).EQ(ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP)) {
2930              /* if we're at the bottom of the stack, then do not install anything */
2931              hijackedReturnAddress = Address.zero();
2932              hijackedReturnCalleeFp = Address.zero();
2933              return;
2934            }
2935            int cmid = Magic.getCompiledMethodID(targetFp);
2936            if (cmid == ArchitectureSpecific.ArchConstants.INVISIBLE_METHOD_ID) {
2937              /* skip invisible methods */
2938              targetFp = Magic.getCallerFramePointer(targetFp);
2939            } else {
2940              CompiledMethod calleeCM = CompiledMethods.getCompiledMethod(cmid);
2941              if (calleeCM.getCompilerType() == CompiledMethod.TRAP ||
2942                  calleeCM.getMethod().getDeclaringClass().hasBridgeFromNativeAnnotation()) {
2943                /* skip traps and native bridges */
2944                targetFp = Magic.getCallerFramePointer(targetFp);
2945              } else
2946                break;
2947            }
2948          }
2949          hijackedReturnAddress = Magic.getReturnAddressUnchecked(targetFp);
2950          hijackedReturnCalleeFp = targetFp;
2951          hijackedReturnCallerFp = Magic.getCallerFramePointer(targetFp);
2952          if (VM.VerifyAssertions) VM._assert(trampoline.NE(hijackedReturnAddress));
2953          if (DEBUG_STACK_TRAMPOLINE) dumpFrame(targetFp);
2954          Magic.setReturnAddress(targetFp, trampoline);
2955          if (DEBUG_STACK_TRAMPOLINE) {
2956            dumpFrame(targetFp);
2957            VM.sysWriteln(getId(), " Installing trampoline at: ", targetFp);
2958            VM.sysWriteln(getId(), " Trampoline: ", trampoline);
2959            VM.sysWriteln(getId(), " Hijacked return address: ", hijackedReturnAddress);
2960            VM.sysWriteln(getId(), " Callee fp: ", hijackedReturnCalleeFp);
2961            VM.sysWriteln(getId(), " Caller fp: ", hijackedReturnCallerFp);
2962            dumpStack(hijackedReturnCalleeFp);
2963          }
2964        }
2965      }
2966    
2967      /**
2968       * de-install the stack trampoline (disabling return barriers).
2969       */
2970      @Uninterruptible
2971      public void deInstallStackTrampoline() {
2972        if (DEBUG_STACK_TRAMPOLINE) VM.sysWriteln("deinstalling trampoline: ", framePointer);
2973        if (!hijackedReturnCalleeFp.isZero()) {
2974          if (DEBUG_STACK_TRAMPOLINE) VM.sysWriteln("need to reinstall: ", hijackedReturnAddress);
2975          hijackedReturnCalleeFp.plus(STACKFRAME_RETURN_ADDRESS_OFFSET).store(hijackedReturnAddress);
2976          hijackedReturnCalleeFp = Address.zero();
2977          hijackedReturnCallerFp = ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP;
2978        }
2979      }
2980    
2981      /** @return the address of the stack trampoline bridge code */
2982      @Inline
2983      private Address getStackTrampolineBridgeIP() { return Magic.objectAsAddress(stackTrampolineBridgeInstructions); }
2984    
2985      /** @return the hijacked return address */
2986      @Inline
2987      public Address getTrampolineHijackedReturnAddress() { return hijackedReturnAddress; }
2988    
2989      /**
2990       * Determine whether a given method is the stack trampoline
2991       *
2992       * @param ip the code to be checked
2993       * @return <code>true</code> if the code is the stack trampoline.
2994       */
2995      @Inline
2996      public static boolean isTrampolineIP(Address ip) { return getCurrentThread().getStackTrampolineBridgeIP().EQ(ip); }
2997    
2998      /**
2999       * Given a frame that has been hijacked by the stack trampoline,
3000       * return the real (hijacked) return address.
3001       *
3002       * @param hijackedFp a frame that has been hijacked by the stack trampoline
3003       * @return the return address for the frame that was hijacked.
3004       */
3005      @Uninterruptible
3006      public static Address getHijackedReturnAddress(Address hijackedFp) {
3007        if (VM.VerifyAssertions) VM._assert(isTrampolineIP(Magic.getReturnAddressUnchecked(hijackedFp)));
3008        RVMThread t = getCurrentThread();
3009          if (!t.hijackedReturnCalleeFp.EQ(hijackedFp)) {
3010            for (int tid = 0; tid < nextSlot; tid++) {
3011              t = threadBySlot[tid];
3012              if (t != null && t.hijackedReturnCalleeFp.EQ(hijackedFp))
3013                break;
3014            }
3015          }
3016          return t.hijackedReturnAddress;
3017      }
3018    
3019      /**
3020       * Dump the specified frame in a format useful for debugging the stack
3021       * trampoline
3022       *
3023       * @param fp The frame to be dumped.
3024       */
3025      private static void dumpFrame(Address fp) {
3026        Address sp = fp.minus(40);
3027        VM.sysWriteln("--");
3028        Address nextFp = Magic.getCallerFramePointer(fp);
3029        while (sp.LE(nextFp)) {
3030          VM.sysWrite("["); VM.sysWrite(sp); VM.sysWrite("]");
3031          if (sp.EQ(fp) || sp.EQ(nextFp)) VM.sysWrite("* ");
3032          else if (sp.EQ(fp.plus(STACKFRAME_RETURN_ADDRESS_OFFSET)) || sp.EQ(nextFp.plus(STACKFRAME_RETURN_ADDRESS_OFFSET))) VM.sysWrite("R ");
3033          else if (sp.EQ(fp.plus(STACKFRAME_METHOD_ID_OFFSET)) || sp.EQ(nextFp.plus(STACKFRAME_METHOD_ID_OFFSET))) VM.sysWrite("M ");
3034          else VM.sysWrite(" ");
3035          VM.sysWriteln(sp.loadInt());
3036          sp = sp.plus(4);
3037        }
3038      }
3039    
3040      /**
3041       * @return the caller of the frame in which the trampoline is installed (STACKFRAME_SENTINEL_FP by default)
3042       */
3043      public Address getNextUnencounteredFrame() {
3044        return hijackedReturnCallerFp.EQ(ArchitectureSpecific.StackframeLayoutConstants.STACKFRAME_SENTINEL_FP) ? hijackedReturnCallerFp : Magic.getCallerFramePointer(hijackedReturnCallerFp);
3045      }
3046    
3047      /**
3048       * Yieldpoint taken in epilogue.
3049       */
3050      @BaselineSaveLSRegisters
3051      // Save all non-volatile registers in prologue
3052      @NoOptCompile
3053      @NoInline
3054      // We should also have a pragma that saves all non-volatiles in opt compiler,
3055      // BaselineExecutionStateExtractor.java, should then restore all non-volatiles
3056      // before stack replacement
3057      // TODO fix this -- related to SaveVolatile
3058      @Entrypoint
3059      @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process")
3060      public static void yieldpointFromEpilogue() {
3061        Address fp = Magic.getFramePointer();
3062        yieldpoint(EPILOGUE, fp);
3063      }
3064    
3065      /*
3066       * Support for suspend/resume
3067       */
3068    
3069      /**
3070       * Suspend execution of current thread until it is resumed. Call only if
3071       * caller has appropriate security clearance.
3072       */
3073      @UnpreemptibleNoWarn("Exceptions may possibly cause yields")
3074      public void suspend() {
3075        if (false) VM.sysWriteln("Thread #",getCurrentThreadSlot()," suspending Thread #",getThreadSlot());
3076        ObjectModel.genericUnlock(thread);
3077        Throwable rethrow = null;
3078        try {
3079          observeExecStatus();
3080          if (execStatus != IN_JAVA && execStatus != IN_JAVA_TO_BLOCK &&
3081              execStatus != IN_NATIVE && execStatus != BLOCKED_IN_NATIVE &&
3082              execStatus != BLOCKED_IN_JNI && execStatus != IN_JNI) {
3083            throw new IllegalThreadStateException(
3084              "Cannot suspend a thread that is not running.");
3085          }
3086          block(suspendBlockAdapter);
3087        } catch (Throwable t) {
3088          rethrow = t;
3089        }
3090        ObjectModel.genericLock(thread);
3091        if (rethrow != null)
3092          RuntimeEntrypoints.athrow(rethrow);
3093      }
3094    
3095      /**
3096       * Resume execution of a thread that has been suspended. Call only if caller
3097       * has appropriate security clearance.
3098       */
3099      @Interruptible
3100      public void resume() {
3101        unblock(suspendBlockAdapter);
3102      }
3103    
3104      public static void yieldNoHandshake() {
3105        sysCall.sysThreadYield();
3106      }
3107    
3108      @UnpreemptibleNoWarn
3109      public static void yieldWithHandshake() {
3110        getCurrentThread().checkBlock();
3111        sysCall.sysThreadYield();
3112      }
3113      /**
3114       * Suspend execution of current thread for specified number of seconds (or
3115       * fraction).
3116       */
3117      @Interruptible
3118      public static void sleep(long ns) throws InterruptedException {
3119        RVMThread t = getCurrentThread();
3120        t.waiting = Waiting.TIMED_WAITING;
3121        long atStart = sysCall.sysNanoTime();
3122        long whenEnd = atStart + ns;
3123        t.monitor().lockNoHandshake();
3124        while (!t.hasInterrupt && t.asyncThrowable == null &&
3125            sysCall.sysNanoTime() < whenEnd) {
3126          t.monitor().timedWaitAbsoluteWithHandshake(whenEnd);
3127        }
3128        boolean throwInterrupt = false;
3129        Throwable throwThis = null;
3130        if (t.hasInterrupt) {
3131          t.hasInterrupt = false;
3132          throwInterrupt = true;
3133        }
3134        if (t.asyncThrowable != null) {
3135          throwThis = t.asyncThrowable;
3136          t.asyncThrowable = null;
3137        }
3138        t.monitor().unlock();
3139        t.waiting = Waiting.RUNNABLE;
3140        if (throwThis != null) {
3141          RuntimeEntrypoints.athrow(throwThis);
3142        }
3143        if (throwInterrupt) {
3144          throw new InterruptedException("sleep interrupted");
3145        }
3146      }
3147    
3148      /**
3149       * Suspend execution of current thread for specified number of seconds (or
3150       * fraction).
3151       */
3152      @Interruptible
3153      public static void sleep(long millis, int ns) throws InterruptedException {
3154        sleep(ns + millis * 1000L * 1000L);
3155      }
3156    
3157      /*
3158       * Wait and notify support
3159       */
3160    
3161      @Interruptible
3162      void waitImpl(Object o, boolean hasTimeout, long whenWakeupNanos) {
3163        boolean throwInterrupt = false;
3164        Throwable throwThis = null;
3165        if (asyncThrowable != null) {
3166          throwThis = asyncThrowable;
3167          asyncThrowable = null;
3168        } else if (!ObjectModel.holdsLock(o, this)) {
3169          throw new IllegalMonitorStateException("waiting on " + o);
3170        } else if (hasInterrupt) {
3171          throwInterrupt = true;
3172          hasInterrupt = false;
3173        } else {
3174          waiting = hasTimeout ? Waiting.TIMED_WAITING : Waiting.WAITING;
3175          // get lock for object
3176          Lock l = ObjectModel.getHeavyLock(o, true);
3177    
3178          // release the lock
3179          l.mutex.lock();
3180          // this thread is supposed to own the lock on o
3181          if (VM.VerifyAssertions) VM._assert(l.getOwnerId() == getLockingId());
3182          RVMThread toAwaken = l.entering.dequeue();
3183          waitObject = l.getLockedObject();
3184          waitCount = l.getRecursionCount();
3185          l.setOwnerId(0);
3186          l.waiting.enqueue(this);
3187          l.mutex.unlock();
3188    
3189          // if there was a thread waiting, awaken it
3190          if (toAwaken != null) {
3191            // is this where the problem is coming from?
3192            toAwaken.monitor().lockedBroadcastNoHandshake();
3193          }
3194          // block
3195          monitor().lockNoHandshake();
3196          while (l.waiting.isQueued(this) && !hasInterrupt && asyncThrowable == null &&
3197                 (!hasTimeout || sysCall.sysNanoTime() < whenWakeupNanos)) {
3198            if (hasTimeout) {
3199              monitor().timedWaitAbsoluteWithHandshake(whenWakeupNanos);
3200            } else {
3201              monitor().waitWithHandshake();
3202            }
3203          }
3204          // figure out if anything special happened while we were blocked
3205          if (hasInterrupt) {
3206            throwInterrupt = true;
3207            hasInterrupt = false;
3208          }
3209          if (asyncThrowable != null) {
3210            throwThis = asyncThrowable;
3211            asyncThrowable = null;
3212          }
3213          monitor().unlock();
3214          if (l.waiting.isQueued(this)) {
3215            l.mutex.lock();
3216            l.waiting.remove(this); /*
3217                                     * in case we got here due to an interrupt or a
3218                                     * stop() rather than a notify
3219                                     */
3220            l.mutex.unlock();
3221            // Note that the above must be done before attempting to acquire
3222            // the lock, since acquiring the lock may require queueing the thread.
3223            // But we cannot queue the thread if it is already on another
3224            // queue.
3225          }
3226          // reacquire the lock, restoring the recursion count
3227          ObjectModel.genericLock(o);
3228          waitObject = null;
3229          if (waitCount != 1) { // reset recursion count
3230            Lock l2 = ObjectModel.getHeavyLock(o, true);
3231            l2.setRecursionCount(waitCount);
3232          }
3233          waiting = Waiting.RUNNABLE;
3234        }
3235        // check if we should exit in a special way
3236        if (throwThis != null) {
3237          RuntimeEntrypoints.athrow(throwThis);
3238        }
3239        if (throwInterrupt) {
3240          RuntimeEntrypoints.athrow(new InterruptedException("sleep interrupted"));
3241        }
3242      }
3243    
3244      /**
3245       * Support for Java {@link java.lang.Object#wait()} synchronization primitive.
3246       *
3247       * @param o
3248       *          the object synchronized on
3249       */
3250      @Interruptible
3251      /* only loses control at expected points -- I think -dave */
3252      public static void wait(Object o) {
3253        getCurrentThread().waitImpl(o, false, 0);
3254      }
3255    
3256      /**
3257       * Support for Java {@link java.lang.Object#wait()} synchronization primitive.
3258       *
3259       * @param o
3260       *          the object synchronized on
3261       * @param millis
3262       *          the number of milliseconds to wait for notification
3263       */
3264      @Interruptible
3265      public static void wait(Object o, long millis) {
3266        long currentNanos = sysCall.sysNanoTime();
3267        getCurrentThread().waitImpl(o, true, currentNanos + millis * 1000 * 1000);
3268      }
3269    
3270      /**
3271       * Support for RTSJ- and pthread-style absolute wait.
3272       *
3273       * @param o
3274       *          the object synchronized on
3275       * @param whenNanos
3276       *          the absolute time in nanoseconds when we should wake up
3277       */
3278      @Interruptible
3279      public static void waitAbsoluteNanos(Object o, long whenNanos) {
3280        getCurrentThread().waitImpl(o, true, whenNanos);
3281      }
3282    
3283      @UnpreemptibleNoWarn("Possible context when generating exception")
3284      public static void raiseIllegalMonitorStateException(String msg, Object o) {
3285        throw new IllegalMonitorStateException(msg + (o == null ? "<null>" : o.toString()));
3286      }
3287    
3288      /**
3289       * Support for Java {@link java.lang.Object#notify()} synchronization
3290       * primitive.
3291       *
3292       * @param o the object synchronized on
3293       */
3294      @Interruptible
3295      public static void notify(Object o) {
3296        if (STATS)
3297          notifyOperations++;
3298        Lock l = ObjectModel.getHeavyLock(o, false);
3299        if (l == null)
3300          return;
3301        // the reason for locking: when inflating a lock we *first* install it in the status
3302        // word and *then* initialize its state.  but fortunately, we do so while holding
3303        // the lock's mutex.  thus acquiring the lock's mutex is the only way to ensure that
3304        // we see the lock's state after initialization.
3305        l.mutex.lock();
3306        int owner=l.getOwnerId();
3307        l.mutex.unlock();
3308        int me=getCurrentThread().getLockingId();
3309        if (owner != me) {
3310          raiseIllegalMonitorStateException("notifying (expected lock to be held by "+me+"("+getCurrentThread().getLockingId()+") but was held by "+owner+"("+l.getOwnerId()+")) ", o);
3311        }
3312        l.mutex.lock();
3313        RVMThread toAwaken = l.waiting.dequeue();
3314        l.mutex.unlock();
3315        if (toAwaken != null) {
3316          toAwaken.monitor().lockedBroadcastNoHandshake();
3317        }
3318      }
3319    
3320      /**
3321       * Support for Java synchronization primitive.
3322       *
3323       * @param o the object synchronized on
3324       * @see java.lang.Object#notifyAll
3325       */
3326      @Interruptible
3327      public static void notifyAll(Object o) {
3328        if (STATS)
3329          notifyAllOperations++;
3330        Lock l = ObjectModel.getHeavyLock(o, false);
3331        if (l == null)
3332          return;
3333        l.mutex.lock();
3334        int owner=l.getOwnerId();
3335        l.mutex.unlock();
3336        if (owner != getCurrentThread().getLockingId()) {
3337          raiseIllegalMonitorStateException("notifying all (expected lock to be held by "+getCurrentThread().getLockingId()+" but was held by "+l.getOwnerId()+") ", o);
3338        }
3339        for (;;) {
3340          l.mutex.lock();
3341          RVMThread toAwaken = l.waiting.dequeue();
3342          l.mutex.unlock();
3343          if (toAwaken == null)
3344            break;
3345          toAwaken.monitor().lockedBroadcastNoHandshake();
3346        }
3347      }
3348    
3349      public void stop(Throwable cause) {
3350        monitor().lockNoHandshake();
3351        asyncThrowable = cause;
3352        takeYieldpoint = 1;
3353        monitor().broadcast();
3354        monitor().unlock();
3355      }
3356    
3357      /*
3358       * Park and unpark support
3359       */
3360      @Interruptible
3361      public void park(boolean isAbsolute, long time) throws Throwable {
3362        if (parkingPermit) {
3363          // fast path
3364          parkingPermit = false;
3365          Magic.sync();
3366          return;
3367        }
3368        // massive retardation. someone might be holding the java.lang.Thread lock.
3369        boolean holdsLock = holdsLock(thread);
3370        if (holdsLock)
3371          ObjectModel.genericUnlock(thread);
3372        boolean hasTimeout;
3373        long whenWakeupNanos;
3374        hasTimeout = (time != 0);
3375        if (isAbsolute) {
3376          whenWakeupNanos = time;
3377        } else {
3378          whenWakeupNanos = sysCall.sysNanoTime() + time;
3379        }
3380        Throwable throwThis = null;
3381        monitor().lockNoHandshake();
3382        waiting = hasTimeout ? Waiting.TIMED_WAITING : Waiting.WAITING;
3383        while (!parkingPermit && !hasInterrupt && asyncThrowable == null &&
3384               (!hasTimeout || sysCall.sysNanoTime() < whenWakeupNanos)) {
3385          if (hasTimeout) {
3386            monitor().timedWaitAbsoluteWithHandshake(whenWakeupNanos);
3387          } else {
3388            monitor().waitWithHandshake();
3389          }
3390        }
3391        waiting = Waiting.RUNNABLE;
3392        parkingPermit = false;
3393        if (asyncThrowable != null) {
3394          throwThis = asyncThrowable;
3395          asyncThrowable = null;
3396        }
3397        monitor().unlock();
3398    
3399        if (holdsLock)
3400          ObjectModel.genericLock(thread);
3401    
3402        if (throwThis != null) {
3403          throw throwThis;
3404        }
3405      }
3406    
3407      @Interruptible
3408      public void unpark() {
3409        monitor().lockNoHandshake();
3410        parkingPermit = true;
3411        monitor().broadcast();
3412        monitor().unlock();
3413      }
3414    
3415      /**
3416       * Get this thread's id for use in lock ownership tests. This is just the
3417       * thread's slot as returned by {@link #getThreadSlot()}, shifted appropriately
3418       * so it can be directly used in the ownership tests.
3419       */
3420      public int getLockingId() {
3421        return lockingId;
3422      }
3423    
3424      @Uninterruptible
3425      public static class SoftHandshakeVisitor {
3426        /**
3427         * Set whatever flags need to be set to signal that the given thread should
3428         * perform some action when it acknowledges the soft handshake. If not
3429         * interested in this thread, return false; otherwise return true. Returning
3430         * true will cause a soft handshake request to be put through.
3431         * <p>
3432         * This method is called with the thread's monitor() held, but while the
3433         * thread may still be running. This method is not called on mutators that
3434         * have indicated that they are about to terminate.
3435         */
3436        public boolean checkAndSignal(RVMThread t) {
3437          return true;
3438        }
3439    
3440        /**
3441         * Called when it is determined that the thread is stuck in native. While
3442         * this method is being called, the thread cannot return to running Java
3443         * code. As such, it is safe to perform actions "on the thread's behalf".
3444         */
3445        public void notifyStuckInNative(RVMThread t) {
3446        }
3447    
3448        /**
3449         * Check whether to include the specified thread in the soft handshake.
3450         *
3451         * @param t The thread to check for inclusion
3452         * @return True if the thread should be included.
3453         */
3454        public boolean includeThread(RVMThread t) {
3455          return true;
3456        }
3457      }
3458    
3459      @NoCheckStore
3460      public static int snapshotHandshakeThreads(SoftHandshakeVisitor v) {
3461        // figure out which threads to consider
3462        acctLock.lockNoHandshake(); /* get a consistent view of which threads are live. */
3463    
3464        int numToHandshake = 0;
3465        for (int i = 0; i < numThreads; ++i) {
3466          RVMThread t = threads[i];
3467          if (t != RVMThread.getCurrentThread() && !t.ignoreHandshakesAndGC() && v.includeThread(t)) {
3468            handshakeThreads[numToHandshake++] = t;
3469          }
3470        }
3471        acctLock.unlock();
3472        return numToHandshake;
3473      }
3474    
3475      /**
3476       * Tell each thread to take a yieldpoint and wait until all of them have done
3477       * so at least once. Additionally, call the visitor on each thread when making
3478       * the yieldpoint request; the purpose of the visitor is to set any additional
3479       * fields as needed to make specific requests to the threads that yield. Note
3480       * that the visitor's <code>visit()</code> method is called with both the
3481       * thread's monitor held, and the <code>softHandshakeDataLock</code> held.
3482       * <p>
3483       * Currently we only use this mechanism for code patch isync requests on PPC,
3484       * but this mechanism is powerful enough to be used by sliding-views style
3485       * concurrent GC.
3486       */
3487      @NoCheckStore
3488      @Unpreemptible("Does not perform actions that lead to blocking, but may wait for threads to rendezvous with the soft handshake")
3489      public static void softHandshake(SoftHandshakeVisitor v) {
3490        handshakeLock.lockWithHandshake(); /*
3491                                            * prevent multiple (soft or hard) handshakes
3492                                            * from proceeding concurrently
3493                                            */
3494    
3495        int numToHandshake = snapshotHandshakeThreads(v);
3496        if (VM.VerifyAssertions)
3497          VM._assert(softHandshakeLeft == 0);
3498    
3499        // in turn, check if each thread needs a handshake, and if so,
3500        // request one
3501        for (int i = 0; i < numToHandshake; ++i) {
3502          RVMThread t = handshakeThreads[i];
3503          handshakeThreads[i] = null; // help GC
3504          t.monitor().lockNoHandshake();
3505          boolean waitForThisThread = false;
3506          if (!t.isAboutToTerminate && v.checkAndSignal(t)) {
3507            // CAS the execStatus field
3508            t.setBlockedExecStatus();
3509            // Note that at this point if the thread tries to either enter or
3510            // exit Java code, it will be diverted into either
3511            // enterNativeBlocked() or checkBlock(), both of which cannot do
3512            // anything until they acquire the monitor() lock, which we now
3513            // hold. Thus, the code below can, at its leisure, examine the
3514            // thread's state and make its decision about what to do, fully
3515            // confident that the thread's state is blocked from changing.
3516            if (t.isInJava()) {
3517              // the thread is currently executing Java code, so we must ensure
3518              // that it either:
3519              // 1) takes the next yieldpoint and rendezvous with this soft
3520              // handshake request (see yieldpoint), or
3521              // 2) performs the rendezvous when leaving Java code
3522              // (see enterNativeBlocked, checkBlock, and addAboutToTerminate)
3523              // either way, we will wait for it to get there before exiting
3524              // this call, since the caller expects that after softHandshake()
3525              // returns, no thread will be running Java code without having
3526              // acknowledged.
3527              t.softHandshakeRequested = true;
3528              t.takeYieldpoint = 1;
3529              waitForThisThread = true;
3530            } else {
3531              // the thread is not in Java code (it may be blocked or it may be
3532              // in native), so we don't have to wait for it since it will
3533              // do the Right Thing before returning to Java code. essentially,
3534              // the thread cannot go back to running Java without doing whatever
3535              // was requested because:
3536              // A) we've set the execStatus to blocked, and
3537              // B) we're holding its lock.
3538              v.notifyStuckInNative(t);
3539            }
3540          }
3541          t.monitor().unlock();
3542    
3543          // NOTE: at this point the thread may already decrement the
3544          // softHandshakeLeft counter, causing it to potentially go negative.
3545          // this is unlikely and completely harmless.
3546    
3547          if (waitForThisThread) {
3548            softHandshakeDataLock.lockNoHandshake();
3549            softHandshakeLeft++;
3550            softHandshakeDataLock.unlock();
3551          }
3552        }
3553    
3554        // wait for all threads to reach the handshake
3555        softHandshakeDataLock.lockNoHandshake();
3556        if (VM.VerifyAssertions)
3557          VM._assert(softHandshakeLeft >= 0);
3558        while (softHandshakeLeft > 0) {
3559          // wait and tell the world that we're off in native land. this way
3560          // if someone tries to block us at this point (suspend() or GC),
3561          // they'll know not to wait for us.
3562          softHandshakeDataLock.waitWithHandshake();
3563        }
3564        if (VM.VerifyAssertions)
3565          VM._assert(softHandshakeLeft == 0);
3566        softHandshakeDataLock.unlock();
3567    
3568        processAboutToTerminate();
3569    
3570        handshakeLock.unlock();
3571      }
3572    
3573      /**
3574       * Check and clear the need for a soft handshake rendezvous.  This method
3575       * cannot do anything that leads to a write barrier or allocation.
3576       */
3577      public boolean softRendezvousCheckAndClear() {
3578        boolean result = false;
3579        monitor().lockNoHandshake();
3580        if (softHandshakeRequested) {
3581          softHandshakeRequested = false;
3582          result = true;
3583        }
3584        monitor().unlock();
3585        return result;
3586      }
3587    
3588      /**
3589       * Commit the soft handshake rendezvous.  This method cannot do anything
3590       * that leads to a write barrier or allocation.
3591       */
3592      public void softRendezvousCommit() {
3593        softHandshakeDataLock.lockNoHandshake();
3594        softHandshakeLeft--;
3595        if (softHandshakeLeft == 0) {
3596          softHandshakeDataLock.broadcast();
3597        }
3598        softHandshakeDataLock.unlock();
3599      }
3600    
3601      /**
3602       * Rendezvous with a soft handshake request. Can only be called when the
3603       * thread's monitor is held.
3604       */
3605      public void softRendezvous() {
3606        if (softRendezvousCheckAndClear())
3607          softRendezvousCommit();
3608      }
3609    
3610      /**
3611       * Handle requests that required a soft handshake. May be called after we
3612       * acknowledged the soft handshake. Thus - this is for actions in which it is
3613       * sufficient for the thread to acknowledge that it plans to act upon the
3614       * request in the immediate future, rather than that the thread acts upon the
3615       * request prior to acknowledging.
3616       * <p>
3617       * This is almost always called with the monitor() lock held, but that's
3618       * not guaranteed.  If you need that lock, you can grab it (since it's a
3619       * recursive lock).  But you should avoid grabbing other sorts of locks since
3620       * that might cause deadlock.
3621       */
3622      void handleHandshakeRequest() {
3623        // Process request for code-patch memory sync operation
3624        if (VM.BuildForPowerPC && codePatchSyncRequested) {
3625          codePatchSyncRequested = false;
3626          // Q: Is this sufficient? Ask Steve why we don't need to sync
3627          // icache/dcache. --dave
3628          // A: Yes, this is sufficient. We (Filip and Dave) talked about it and
3629          // agree that remote processors only need to execute isync. --Filip
3630          // make sure not get stale data
3631          Magic.isync();
3632        }
3633        // process memory management requests
3634        if (flushRequested && activeMutatorContext) {
3635          MemoryManager.flushMutatorContext();
3636          flushRequested = false;
3637        }
3638        // not really a "soft handshake" request but we handle it here anyway
3639        if (asyncDebugRequestedForThisThread) {
3640          asyncDebugRequestedForThisThread = false;
3641          dumpLock.lockNoHandshake();
3642          VM.sysWriteln("Handling async stack trace request...");
3643          dump();
3644          VM.sysWriteln();
3645          dumpStack();
3646          dumpLock.unlock();
3647        }
3648      }
3649    
3650      /**
3651       * Stop all mutator threads. This is current intended to be run by a single thread.
3652       *
3653       * Fixpoint until there are no threads that we haven't blocked. Fixpoint is needed to
3654       * catch the (unlikely) case that a thread spawns another thread while we are waiting.
3655       */
3656      @NoCheckStore
3657      @Unpreemptible
3658      public static void blockAllMutatorsForGC() {
3659        RVMThread.handshakeLock.lockNoHandshake();
3660        while (true) {
3661          // (1) Find all the threads that need to be blocked for GC
3662          RVMThread.acctLock.lockNoHandshake();
3663          int numToHandshake = 0;
3664          for (int i = 0; i < RVMThread.numThreads; i++) {
3665            RVMThread t = RVMThread.threads[i];
3666            if (!t.isCollectorThread() && !t.ignoreHandshakesAndGC()) {
3667              RVMThread.handshakeThreads[numToHandshake++] = t;
3668            }
3669          }
3670          RVMThread.acctLock.unlock();
3671    
3672          // (2) Remove any threads that have already been blocked from the list.
3673          for (int i = 0; i < numToHandshake; i++) {
3674            RVMThread t = RVMThread.handshakeThreads[i];
3675            t.monitor().lockNoHandshake();
3676            if (t.blockedFor(RVMThread.gcBlockAdapter) || RVMThread.notRunning(t.asyncBlock(RVMThread.gcBlockAdapter))) {
3677              // Already blocked or not running, remove.
3678              RVMThread.handshakeThreads[i--] = RVMThread.handshakeThreads[--numToHandshake];
3679              RVMThread.handshakeThreads[numToHandshake] = null; // help GC
3680            }
3681            t.monitor().unlock();
3682          }
3683    
3684          // (3) Quit trying to block threads if all threads are either blocked
3685          //     or not running (a thread is "not running" if it is NEW or TERMINATED;
3686          //     in the former case it means that the thread has not had start()
3687          //     called on it while in the latter case it means that the thread
3688          //     is either in the TERMINATED state or is about to be in that state
3689          //     real soon now, and will not perform any heap-related work before
3690          //     terminating).
3691          if (numToHandshake == 0) break;
3692    
3693          // (4) Request a block for GC from all other threads.
3694          for (int i = 0; i < numToHandshake; i++) {
3695            if (false) VM.sysWriteln("Waiting for ", RVMThread.handshakeThreads[i].getThreadSlot(), " to block.");
3696            RVMThread t = RVMThread.handshakeThreads[i];
3697            RVMThread.observeExecStatusAtSTW(t.block(RVMThread.gcBlockAdapter));
3698            RVMThread.handshakeThreads[i] = null; // help GC
3699          }
3700        }
3701        RVMThread.handshakeLock.unlock();
3702    
3703        // Deal with terminating threads to ensure that all threads are either dead to MMTk or stopped above.
3704        RVMThread.processAboutToTerminate();
3705      }
3706    
3707      /**
3708       * Unblock all mutators blocked for GC.
3709       */
3710      @NoCheckStore
3711      @Unpreemptible
3712      public static void unblockAllMutatorsForGC() {
3713        RVMThread.handshakeLock.lockNoHandshake();
3714        RVMThread.acctLock.lockNoHandshake();
3715        int numToHandshake = 0;
3716        for (int i = 0; i < RVMThread.numThreads; i++) {
3717          RVMThread t = RVMThread.threads[i];
3718          if (!t.isCollectorThread() && !t.ignoreHandshakesAndGC()) {
3719            RVMThread.handshakeThreads[numToHandshake++] = t;
3720          }
3721        }
3722        RVMThread.acctLock.unlock();
3723        for (int i = 0; i < numToHandshake; i++) {
3724          RVMThread.handshakeThreads[i].unblock(RVMThread.gcBlockAdapter);
3725          RVMThread.handshakeThreads[i] = null; // Help GC
3726        }
3727        RVMThread.handshakeLock.unlock();
3728      }
3729    
3730      @Uninterruptible
3731      public static class HardHandshakeVisitor {
3732        public boolean includeThread(RVMThread t) {
3733          return true;
3734        }
3735      }
3736    
3737      @Uninterruptible
3738      @NonMoving
3739      static class AllButGCHardHandshakeVisitor extends HardHandshakeVisitor {
3740        @Override
3741        public boolean includeThread(RVMThread t) {
3742          return !t.isCollectorThread();
3743        }
3744      }
3745    
3746      public static final AllButGCHardHandshakeVisitor allButGC=
3747        new AllButGCHardHandshakeVisitor();
3748    
3749      static long totalSuspendTime;
3750      static long totalResumeTime;
3751    
3752      @Unpreemptible
3753      @NoCheckStore
3754      public static void hardHandshakeSuspend(BlockAdapter ba,
3755                                              HardHandshakeVisitor hhv) {
3756        long before=sysCall.sysNanoTime();
3757    
3758        RVMThread current=getCurrentThread();
3759    
3760        handshakeLock.lockWithHandshake();
3761        int numLockedLocks=0;
3762        for (int i=0;i<nextSlot;++i) {
3763          Monitor l=communicationLockBySlot[i];
3764          if (l!=null) {
3765            l.lockWithHandshake();
3766            numLockedLocks++;
3767          }
3768        }
3769    
3770        // fixpoint until there are no threads that we haven't blocked.
3771        // fixpoint is needed in case some thread spawns another thread
3772        // while we're waiting.  that is unlikely but possible.
3773        for (;;) {
3774          acctLock.lockNoHandshake();
3775          int numToHandshake=0;
3776          for (int i=0;i<numThreads;++i) {
3777            RVMThread t=threads[i];
3778            if (t!=current &&
3779                !t.ignoreHandshakesAndGC() &&
3780                hhv.includeThread(t)) {
3781              handshakeThreads[numToHandshake++]=t;
3782            }
3783          }
3784          acctLock.unlock();
3785    
3786          for (int i=0;i<numToHandshake;++i) {
3787            RVMThread t=handshakeThreads[i];
3788            t.monitor().lockNoHandshake();
3789            if (t.blockedFor(ba) ||
3790                notRunning(t.asyncBlock(ba))) {
3791              // already blocked or not running, remove
3792              handshakeThreads[i--]=handshakeThreads[--numToHandshake];
3793              handshakeThreads[numToHandshake]=null; // help GC
3794            }
3795            t.monitor().unlock();
3796          }
3797          // quit trying to block threads if all threads are either blocked
3798          // or not running (a thread is "not running" if it is NEW or TERMINATED;
3799          // in the former case it means that the thread has not had start()
3800          // called on it while in the latter case it means that the thread
3801          // is either in the TERMINATED state or is about to be in that state
3802          // real soon now, and will not perform any heap-related stuff before
3803          // terminating).
3804          if (numToHandshake==0) break;
3805          for (int i=0;i<numToHandshake;++i) {
3806            RVMThread t=handshakeThreads[i];
3807            observeExecStatusAtSTW(t.block(ba));
3808            handshakeThreads[i]=null; // help GC
3809          }
3810        }
3811        worldStopped=true;
3812    
3813        processAboutToTerminate(); /*
3814                                    * ensure that any threads that died while
3815                                    * we were stopping the world notify us
3816                                    * that they had stopped.
3817                                    */
3818    
3819        int numUnlockedLocks=0;
3820        for (int i=0;i<nextSlot;++i) {
3821          Monitor l=communicationLockBySlot[i];
3822          if (l!=null) {
3823            l.unlock();
3824            numUnlockedLocks++;
3825          }
3826        }
3827        if (VM.VerifyAssertions) VM._assert(numLockedLocks==numUnlockedLocks);
3828        handshakeLock.unlock();
3829    
3830        if (false) {
3831          long after=sysCall.sysNanoTime();
3832          totalSuspendTime+=after-before;
3833          VM.sysWriteln("Stopping the world took ",(after-before)," ns (",totalSuspendTime," ns total)");
3834        }
3835      }
3836    
3837      @NoCheckStore
3838      @Unpreemptible
3839      public static void hardHandshakeResume(BlockAdapter ba,
3840                                             HardHandshakeVisitor hhv) {
3841        long before=sysCall.sysNanoTime();
3842    
3843        handshakeLock.lockWithHandshake();
3844    
3845        RVMThread current=getCurrentThread();
3846        worldStopped=false;
3847        acctLock.lockNoHandshake();
3848        int numToHandshake=0;
3849        for (int i=0;i<numThreads;++i) {
3850          RVMThread t=threads[i];
3851          if (t!=current &&
3852              !t.ignoreHandshakesAndGC() &&
3853              hhv.includeThread(t)) {
3854            handshakeThreads[numToHandshake++]=t;
3855          }
3856        }
3857        acctLock.unlock();
3858        for (int i=0;i<numToHandshake;++i) {
3859          handshakeThreads[i].unblock(ba);
3860          handshakeThreads[i]=null; // help GC
3861        }
3862    
3863        handshakeLock.unlock();
3864    
3865        if (false) {
3866          long after=sysCall.sysNanoTime();
3867          totalResumeTime+=after-before;
3868          VM.sysWriteln("Resuming the world took ",(after-before)," ns (",totalResumeTime," ns total)");
3869        }
3870      }
3871    
3872      @Unpreemptible
3873      public static void hardHandshakeSuspend() {
3874        hardHandshakeSuspend(handshakeBlockAdapter,allButGC);
3875      }
3876    
3877      @Unpreemptible
3878      public static void hardHandshakeResume() {
3879        hardHandshakeResume(handshakeBlockAdapter,allButGC);
3880      }
3881    
3882      public static boolean worldStopped() {
3883        return worldStopped;
3884      }
3885    
3886      /**
3887       * Process a taken yieldpoint.
3888       */
3889      @Unpreemptible("May block if the thread was asked to do so but otherwise does not perform actions that may lead to blocking")
3890      public static void yieldpoint(int whereFrom, Address yieldpointServiceMethodFP) {
3891        RVMThread t = getCurrentThread();
3892        boolean wasAtYieldpoint = t.atYieldpoint;
3893        t.atYieldpoint = true;
3894        t.yieldpointsTaken++;
3895        // If thread is in critical section we can't do anything right now, defer
3896        // until later
3897        // we do this without acquiring locks, since part of the point of disabling
3898        // yieldpoints is to ensure that locks are not "magically" acquired
3899        // through unexpected yieldpoints. As well, this makes code running with
3900        // yieldpoints disabled more predictable. Note furthermore that the only
3901        // race here is setting takeYieldpoint to 0. But this is perfectly safe,
3902        // since we are guaranteeing that a yieldpoint will run after we emerge from
3903        // the no-yieldpoints code. At worst, setting takeYieldpoint to 0 will be
3904        // lost (because some other thread sets it to non-0), but in that case we'll
3905        // just come back here and reset it to 0 again.
3906        if (!t.yieldpointsEnabled()) {
3907          if (VM.VerifyAssertions)
3908            VM._assert(!t.yieldToOSRRequested);
3909          if (traceBlock && !wasAtYieldpoint) {
3910            VM.sysWriteln("Thread #", t.threadSlot, " deferring yield!");
3911            dumpStack();
3912          }
3913          t.yieldpointRequestPending = true;
3914          t.takeYieldpoint = 0;
3915          t.atYieldpoint = false;
3916          return;
3917        }
3918        t.yieldpointsTakenFully++;
3919    
3920        Throwable throwThis = null;
3921        t.monitor().lockNoHandshake();
3922    
3923        int takeYieldpointVal = t.takeYieldpoint;
3924        if (takeYieldpointVal != 0) {
3925          t.takeYieldpoint = 0;
3926          // do two things: check if we should be blocking, and act upon
3927          // handshake requests. This also has the effect of reasserting that
3928          // we are in fact IN_JAVA (as opposed to IN_JAVA_TO_BLOCK).
3929          t.checkBlock();
3930    
3931          // Process timer interrupt event
3932          if (t.timeSliceExpired != 0) {
3933            t.timeSliceExpired = 0;
3934    
3935            if (t.yieldForCBSCall || t.yieldForCBSMethod) {
3936              /*
3937               * CBS Sampling is still active from previous quantum. Note that fact,
3938               * but leave all the other CBS parameters alone.
3939               */
3940            } else {
3941              if (VM.CBSCallSamplesPerTick > 0) {
3942                t.yieldForCBSCall = true;
3943                t.takeYieldpoint = -1;
3944                t.firstCBSCallSample++;
3945                t.firstCBSCallSample = t.firstCBSCallSample % VM.CBSCallSampleStride;
3946                t.countdownCBSCall = t.firstCBSCallSample;
3947                t.numCBSCallSamples = VM.CBSCallSamplesPerTick;
3948              }
3949    
3950              if (VM.CBSMethodSamplesPerTick > 0) {
3951                t.yieldForCBSMethod = true;
3952                t.takeYieldpoint = -1;
3953                t.firstCBSMethodSample++;
3954                t.firstCBSMethodSample = t.firstCBSMethodSample % VM.CBSMethodSampleStride;
3955                t.countdownCBSMethod = t.firstCBSMethodSample;
3956                t.numCBSMethodSamples = VM.CBSMethodSamplesPerTick;
3957              }
3958            }
3959    
3960            if (VM.BuildForAdaptiveSystem) {
3961              RuntimeMeasurements.takeTimerSample(whereFrom,
3962                  yieldpointServiceMethodFP);
3963            }
3964            if (VM.BuildForAdaptiveSystem) {
3965              OSRListener
3966                  .checkForOSRPromotion(whereFrom, yieldpointServiceMethodFP);
3967            }
3968          }
3969    
3970          if (t.yieldForCBSCall) {
3971            if (!(whereFrom == BACKEDGE || whereFrom == OSROPT)) {
3972              if (--t.countdownCBSCall <= 0) {
3973                if (VM.BuildForAdaptiveSystem) {
3974                  // take CBS sample
3975                  RuntimeMeasurements.takeCBSCallSample(whereFrom,
3976                      yieldpointServiceMethodFP);
3977                }
3978                t.countdownCBSCall = VM.CBSCallSampleStride;
3979                t.numCBSCallSamples--;
3980                if (t.numCBSCallSamples <= 0) {
3981                  t.yieldForCBSCall = false;
3982                }
3983              }
3984            }
3985            if (t.yieldForCBSCall) {
3986              t.takeYieldpoint = -1;
3987            }
3988          }
3989    
3990          if (t.yieldForCBSMethod) {
3991            if (--t.countdownCBSMethod <= 0) {
3992              if (VM.BuildForAdaptiveSystem) {
3993                // take CBS sample
3994                RuntimeMeasurements.takeCBSMethodSample(whereFrom,
3995                    yieldpointServiceMethodFP);
3996              }
3997              t.countdownCBSMethod = VM.CBSMethodSampleStride;
3998              t.numCBSMethodSamples--;
3999              if (t.numCBSMethodSamples <= 0) {
4000                t.yieldForCBSMethod = false;
4001              }
4002            }
4003            if (t.yieldForCBSMethod) {
4004              t.takeYieldpoint = 1;
4005            }
4006          }
4007    
4008          if (VM.BuildForAdaptiveSystem && t.yieldToOSRRequested) {
4009            t.yieldToOSRRequested = false;
4010            OSRListener.handleOSRFromOpt(yieldpointServiceMethodFP);
4011          }
4012    
4013          // what is the reason for this? and what was the reason for doing
4014          // a thread switch following the suspension in the OSR trigger code?
4015          // ... it seems that at least part of the point here is that if a
4016          // thread switch was desired for other reasons, then we need to ensure
4017          // that between when this runs and when the glue code runs there will
4018          // be no interleaved GC; obviously if we did this before the thread
4019          // switch then there would be the possibility of interleaved GC.
4020          if (VM.BuildForAdaptiveSystem && t.isWaitingForOsr) {
4021            PostThreadSwitch.postProcess(t);
4022          }
4023          if (t.asyncThrowable != null) {
4024            throwThis = t.asyncThrowable;
4025            t.asyncThrowable = null;
4026          }
4027        }
4028        t.monitor().unlock();
4029        t.atYieldpoint = false;
4030        if (throwThis != null) {
4031          throwFromUninterruptible(throwThis);
4032        }
4033      }
4034    
4035      @Unpreemptible
4036      private static void throwFromUninterruptible(Throwable e) {
4037        RuntimeEntrypoints.athrow(e);
4038      }
4039    
4040      /**
4041       * Change the size of the currently executing thread's stack.
4042       *
4043       * @param newSize
4044       *          new size (in bytes)
4045       * @param exceptionRegisters
4046       *          register state at which stack overflow trap was encountered (null
4047       *          --> normal method call, not a trap)
4048       */
4049      @Unpreemptible("May block due to allocation")
4050      public static void resizeCurrentStack(int newSize,
4051          Registers exceptionRegisters) {
4052        if (!getCurrentThread().hijackedReturnAddress.isZero()) {
4053          /* stack resizing currently unsupported with return barrier */
4054          VM.sysFail("system error: resizing stack while return barrier enabled (currently unsupported)");
4055        }
4056        if (traceAdjustments)
4057          VM.sysWrite("Thread: resizeCurrentStack\n");
4058        if (MemoryManager.gcInProgress()) {
4059          VM.sysFail("system error: resizing stack while GC is in progress");
4060        }
4061        byte[] newStack = MemoryManager.newStack(newSize);
4062        getCurrentThread().disableYieldpoints();
4063        transferExecutionToNewStack(newStack, exceptionRegisters);
4064        getCurrentThread().enableYieldpoints();
4065        if (traceAdjustments) {
4066          RVMThread t = getCurrentThread();
4067          VM.sysWrite("Thread: resized stack ", t.getThreadSlot());
4068          VM.sysWrite(" to ", t.stack.length / 1024);
4069          VM.sysWrite("k\n");
4070        }
4071      }
4072    
4073      @NoInline
4074      @BaselineNoRegisters
4075      // this method does not do a normal return and hence does not execute epilogue
4076      // --> non-volatiles not restored!
4077      private static void transferExecutionToNewStack(byte[] newStack,
4078          Registers exceptionRegisters) {
4079        // prevent opt compiler from inlining a method that contains a magic
4080        // (returnToNewStack) that it does not implement.
4081    
4082        RVMThread myThread = getCurrentThread();
4083        byte[] myStack = myThread.stack;
4084    
4085        // initialize new stack with live portion of stack we're
4086        // currently running on
4087        //
4088        // lo-mem hi-mem
4089        // |<---myDepth----|
4090        // +----------+---------------+
4091        // | empty | live |
4092        // +----------+---------------+
4093        // ^myStack ^myFP ^myTop
4094        //
4095        // +-------------------+---------------+
4096        // | empty | live |
4097        // +-------------------+---------------+
4098        // ^newStack ^newFP ^newTop
4099        //
4100        Address myTop = Magic.objectAsAddress(myStack).plus(myStack.length);
4101        Address newTop = Magic.objectAsAddress(newStack).plus(newStack.length);
4102    
4103        Address myFP = Magic.getFramePointer();
4104        Offset myDepth = myTop.diff(myFP);
4105        Address newFP = newTop.minus(myDepth);
4106    
4107        // The frame pointer addresses the top of the frame on powerpc and
4108        // the bottom
4109        // on intel. if we copy the stack up to the current
4110        // frame pointer in here, the
4111        // copy will miss the header of the intel frame. Thus we make another
4112        // call
4113        // to force the copy. A more explicit way would be to up to the
4114        // frame pointer
4115        // and the header for intel.
4116        Offset delta = copyStack(newStack);
4117    
4118        // fix up registers and save areas so they refer
4119        // to "newStack" rather than "myStack"
4120        //
4121        if (exceptionRegisters != null) {
4122          adjustRegisters(exceptionRegisters, delta);
4123        }
4124        adjustStack(newStack, newFP, delta);
4125    
4126        // install new stack
4127        //
4128        myThread.stack = newStack;
4129        myThread.stackLimit = Magic.objectAsAddress(newStack)
4130            .plus(STACK_SIZE_GUARD);
4131    
4132        // return to caller, resuming execution on new stack
4133        // (original stack now abandoned)
4134        //
4135        if (VM.BuildForPowerPC) {
4136          Magic.returnToNewStack(Magic.getCallerFramePointer(newFP));
4137        } else if (VM.BuildForIA32) {
4138          Magic.returnToNewStack(newFP);
4139        }
4140    
4141        if (VM.VerifyAssertions)
4142          VM._assert(VM.NOT_REACHED);
4143      }
4144    
4145      /**
4146       * This (suspended) thread's stack has been moved. Fixup register and memory
4147       * references to reflect its new position.
4148       *
4149       * @param delta
4150       *          displacement to be applied to all interior references
4151       */
4152      public void fixupMovedStack(Offset delta) {
4153        if (traceAdjustments)
4154          VM.sysWrite("Thread: fixupMovedStack\n");
4155    
4156        if (!contextRegisters.getInnermostFramePointer().isZero()) {
4157          adjustRegisters(contextRegisters, delta);
4158        }
4159        if ((exceptionRegisters.inuse) &&
4160            (exceptionRegisters.getInnermostFramePointer().NE(Address.zero()))) {
4161          adjustRegisters(exceptionRegisters, delta);
4162        }
4163        if (!contextRegisters.getInnermostFramePointer().isZero()) {
4164          adjustStack(stack, contextRegisters.getInnermostFramePointer(), delta);
4165        }
4166        stackLimit = stackLimit.plus(delta);
4167      }
4168    
4169      /**
4170       * A thread's stack has been moved or resized. Adjust registers to reflect new
4171       * position.
4172       *
4173       * @param registers
4174       *          registers to be adjusted
4175       * @param delta
4176       *          displacement to be applied
4177       */
4178      private static void adjustRegisters(Registers registers, Offset delta) {
4179        if (traceAdjustments)
4180          VM.sysWrite("Thread: adjustRegisters\n");
4181    
4182        // adjust FP
4183        //
4184        Address newFP = registers.getInnermostFramePointer().plus(delta);
4185        Address ip = registers.getInnermostInstructionAddress();
4186        registers.setInnermost(ip, newFP);
4187        if (traceAdjustments) {
4188          VM.sysWrite(" fp=");
4189          VM.sysWrite(registers.getInnermostFramePointer());
4190        }
4191    
4192        // additional architecture specific adjustments
4193        // (1) frames from all compilers on IA32 need to update ESP
4194        int compiledMethodId = Magic.getCompiledMethodID(registers
4195            .getInnermostFramePointer());
4196        if (compiledMethodId != INVISIBLE_METHOD_ID) {
4197          if (VM.BuildForIA32) {
4198            Configuration.archHelper.adjustESP(registers, delta, traceAdjustments);
4199          }
4200          if (traceAdjustments) {
4201            CompiledMethod compiledMethod = CompiledMethods
4202                .getCompiledMethod(compiledMethodId);
4203            VM.sysWrite(" method=");
4204            VM.sysWrite(compiledMethod.getMethod());
4205            VM.sysWrite("\n");
4206          }
4207        }
4208      }
4209    
4210      /**
4211       * A thread's stack has been moved or resized. Adjust internal pointers to
4212       * reflect new position.
4213       *
4214       * @param stack
4215       *          stack to be adjusted
4216       * @param fp
4217       *          pointer to its innermost frame
4218       * @param delta
4219       *          displacement to be applied to all its interior references
4220       */
4221      private static void adjustStack(byte[] stack, Address fp, Offset delta) {
4222        if (traceAdjustments)
4223          VM.sysWrite("Thread: adjustStack\n");
4224    
4225        while (Magic.getCallerFramePointer(fp).NE(STACKFRAME_SENTINEL_FP)) {
4226          // adjust FP save area
4227          //
4228          Magic.setCallerFramePointer(fp, Magic.getCallerFramePointer(fp).plus(
4229              delta));
4230          if (traceAdjustments) {
4231            VM.sysWrite(" fp=", fp.toWord());
4232          }
4233    
4234          // advance to next frame
4235          //
4236          fp = Magic.getCallerFramePointer(fp);
4237        }
4238      }
4239    
4240      /**
4241       * Initialize a new stack with the live portion of the stack we're currently
4242       * running on.
4243       *
4244       * <pre>
4245       *  lo-mem                                        hi-mem
4246       *                           |&lt;---myDepth----|
4247       *                 +----------+---------------+
4248       *                 |   empty  |     live      |
4249       *                 +----------+---------------+
4250       *                  &circ;myStack   &circ;myFP           &circ;myTop
4251       *       +-------------------+---------------+
4252       *       |       empty       |     live      |
4253       *       +-------------------+---------------+
4254       *        &circ;newStack           &circ;newFP          &circ;newTop
4255       * </pre>
4256       */
4257      private static Offset copyStack(byte[] newStack) {
4258        RVMThread myThread = getCurrentThread();
4259        byte[] myStack = myThread.stack;
4260    
4261        Address myTop = Magic.objectAsAddress(myStack).plus(myStack.length);
4262        Address newTop = Magic.objectAsAddress(newStack).plus(newStack.length);
4263        Address myFP = Magic.getFramePointer();
4264        Offset myDepth = myTop.diff(myFP);
4265        Address newFP = newTop.minus(myDepth);
4266    
4267        // before copying, make sure new stack isn't too small
4268        //
4269        if (VM.VerifyAssertions) {
4270          VM._assert(newFP.GE(Magic.objectAsAddress(newStack)
4271              .plus(STACK_SIZE_GUARD)));
4272        }
4273    
4274        Memory.memcopy(newFP, myFP, myDepth.toWord().toExtent());
4275    
4276        return newFP.diff(myFP);
4277      }
4278    
4279      /**
4280       * Set the "isDaemon" status of this thread. Although a java.lang.Thread can
4281       * only have setDaemon invoked on it before it is started, Threads can become
4282       * daemons at any time. Note: making the last non daemon a daemon will
4283       * terminate the VM.
4284       * <p>
4285       * Note: This method might need to be uninterruptible so it is final, which is
4286       * why it isn't called setDaemon.
4287       * <p>
4288       * Public so that java.lang.Thread can use it.
4289       */
4290      public void makeDaemon(boolean on) {
4291        if (daemon == on) {
4292          // nothing to do
4293        } else {
4294          daemon = on;
4295          if (getExecStatus() == NEW) {
4296            // thread will start as a daemon
4297          } else {
4298            boolean terminateSystem = false;
4299            acctLock.lockNoHandshake();
4300            numActiveDaemons += on ? 1 : -1;
4301            if (numActiveDaemons == numActiveThreads) {
4302              terminateSystem = true;
4303            }
4304            acctLock.unlock();
4305            if (terminateSystem) {
4306              if (VM.TraceThreads) {
4307                trace("Thread", "last non Daemon demonized");
4308              }
4309              VM.sysExit(0);
4310              if (VM.VerifyAssertions)
4311                VM._assert(VM.NOT_REACHED);
4312            }
4313          }
4314        }
4315      }
4316    
4317      /**
4318       * Dump information for all threads, via {@link VM#sysWrite(String)}. Each
4319       * thread's info is newline-terminated.
4320       *
4321       * @param verbosity Ignored.
4322       */
4323      public static void dumpAll(int verbosity) {
4324        for (int i = 0; i < numThreads; i++) {
4325          RVMThread t = threads[i];
4326          if (t == null)
4327            continue;
4328          VM.sysWrite("Thread ");
4329          VM.sysWriteInt(t.threadSlot);
4330          VM.sysWrite(":  ");
4331          VM.sysWriteHex(Magic.objectAsAddress(t));
4332          VM.sysWrite("   ");
4333          t.dump(verbosity);
4334          // Compensate for t.dump() not newline-terminating info.
4335          VM.sysWriteln();
4336        }
4337      }
4338    
4339      /** @return The value of {@link #isBootThread} */
4340      public boolean isBootThread() {
4341        return this == bootThread;
4342      }
4343    
4344      /** @return Is this the MainThread ? */
4345      private boolean isMainThread() {
4346        return thread instanceof MainThread;
4347      }
4348    
4349      /** Is this a system thread? */
4350      public boolean isSystemThread() {
4351        return systemThread != null;
4352      }
4353    
4354      /** Get the collector thread this RVMTHread is running */
4355      public CollectorThread getCollectorThread() {
4356        if (VM.VerifyAssertions) VM._assert(isCollectorThread());
4357        return (CollectorThread)systemThread;
4358      }
4359    
4360      /** Returns the value of {@link #daemon}. */
4361      public boolean isDaemonThread() {
4362        return daemon;
4363      }
4364    
4365      /**
4366       * Should this thread run concurrently with STW GC and ignore handshakes?
4367       */
4368      public boolean ignoreHandshakesAndGC() {
4369        if (systemThread == null) return false;
4370        return systemThread instanceof TimerThread;
4371      }
4372    
4373      /** Is the thread started and not terminated */
4374      public boolean isAlive() {
4375        monitor().lockNoHandshake();
4376        observeExecStatus();
4377        boolean result = execStatus != NEW && execStatus != TERMINATED && !isAboutToTerminate;
4378        monitor().unlock();
4379        return result;
4380      }
4381    
4382      /**
4383       * Sets the name of the thread
4384       *
4385       * @param name the new name for the thread
4386       * @see java.lang.Thread#setName(String)
4387       */
4388      public void setName(String name) {
4389        this.name = name;
4390      }
4391    
4392      /**
4393       * Gets the name of the thread
4394       *
4395       * @see java.lang.Thread#getName()
4396       */
4397      public String getName() {
4398        return name;
4399      }
4400    
4401      /**
4402       * Does the currently running Thread hold the lock on an obj?
4403       *
4404       * @param obj
4405       *          the object to check
4406       * @return whether the thread holds the lock
4407       * @see java.lang.Thread#holdsLock(Object)
4408       */
4409      public boolean holdsLock(Object obj) {
4410        RVMThread mine = getCurrentThread();
4411        return ObjectModel.holdsLock(obj, mine);
4412      }
4413    
4414      /**
4415       * Was this thread interrupted?
4416       *
4417       * @return whether the thread has been interrupted
4418       * @see java.lang.Thread#isInterrupted()
4419       */
4420      public boolean isInterrupted() {
4421        return hasInterrupt;
4422      }
4423    
4424      /**
4425       * Clear the interrupted status of this thread
4426       *
4427       * @see java.lang.Thread#interrupted()
4428       */
4429      public void clearInterrupted() {
4430        hasInterrupt = false;
4431      }
4432    
4433      /**
4434       * Interrupt this thread
4435       *
4436       * @see java.lang.Thread#interrupt()
4437       */
4438      @Interruptible
4439      public void interrupt() {
4440        monitor().lockNoHandshake();
4441        hasInterrupt = true;
4442        monitor().broadcast();
4443        monitor().unlock();
4444      }
4445    
4446      /**
4447       * Get the priority of the thread
4448       *
4449       * @return the thread's priority
4450       * @see java.lang.Thread#getPriority()
4451       */
4452      public int getPriority() {
4453        return priority;
4454      }
4455    
4456      /**
4457       * Set the priority of the thread
4458       *
4459       * @param priority
4460       * @see java.lang.Thread#getPriority()
4461       */
4462      public void setPriority(int priority) {
4463        this.priority = priority;
4464        // @TODO this should be calling a syscall
4465      }
4466    
4467      /**
4468       * Get the state of the thread in a manner compatible with the Java API
4469       *
4470       * @return thread state
4471       * @see java.lang.Thread#getState()
4472       */
4473      @Interruptible
4474      public Thread.State getState() {
4475        monitor().lockNoHandshake();
4476        try {
4477          observeExecStatus();
4478          switch (execStatus) {
4479          case NEW:
4480            return Thread.State.NEW;
4481          case IN_JAVA:
4482          case IN_NATIVE:
4483          case IN_JNI:
4484          case IN_JAVA_TO_BLOCK:
4485          case BLOCKED_IN_NATIVE:
4486          case BLOCKED_IN_JNI:
4487            if (isAboutToTerminate) {
4488              return Thread.State.TERMINATED;
4489            }
4490            switch (waiting) {
4491            case RUNNABLE:
4492              return Thread.State.RUNNABLE;
4493            case WAITING:
4494              return Thread.State.WAITING;
4495            case TIMED_WAITING:
4496              return Thread.State.TIMED_WAITING;
4497            default:
4498              VM.sysFail("Unknown waiting value: " + waiting);
4499              return null;
4500            }
4501          case TERMINATED:
4502            return Thread.State.TERMINATED;
4503          default:
4504            VM.sysFail("Unknown value of execStatus: " + execStatus);
4505            return null;
4506          }
4507        } finally {
4508          monitor().unlock();
4509        }
4510      }
4511    
4512      /**
4513       * Wait for the thread to die or for the timeout to occur
4514       *
4515       * @param ms
4516       *          milliseconds to wait
4517       * @param ns
4518       *          nanoseconds to wait
4519       */
4520      @Interruptible
4521      public void join(long ms, int ns) throws InterruptedException {
4522        RVMThread myThread = getCurrentThread();
4523        if (VM.VerifyAssertions)
4524          VM._assert(myThread != this);
4525        if (traceBlock)
4526          VM.sysWriteln("Joining on Thread #", threadSlot);
4527        // this uses synchronized because we cannot have one thread acquire
4528        // another thread's lock using the WithHandshake scheme, as that would result
4529        // in a thread holding two threads' monitor()s.  using synchronized
4530        // turns out to be just fine - see comment in terminate().
4531        synchronized (this) {
4532          if (ms == 0 && ns == 0) {
4533            while (!isJoinable) {
4534              wait(this);
4535              if (traceBlock)
4536                VM.sysWriteln("relooping in join on Thread #", threadSlot);
4537            }
4538          } else {
4539            long startNano = Time.nanoTime();
4540            long whenWakeup = startNano + ms * 1000L * 1000L + ns;
4541            while (!isJoinable) {
4542              waitAbsoluteNanos(this, whenWakeup);
4543              if (Time.nanoTime() >= whenWakeup) {
4544                break;
4545              }
4546              if (traceBlock)
4547                VM.sysWriteln("relooping in join on Thread #", threadSlot);
4548            }
4549          }
4550        }
4551      }
4552    
4553      /**
4554       * Count the stack frames of this thread
4555       */
4556      @Interruptible
4557      public int countStackFrames() {
4558        if (!isSuspended) {
4559          throw new IllegalThreadStateException(
4560              "Thread.countStackFrames called on non-suspended thread");
4561        }
4562        throw new UnimplementedError();
4563      }
4564    
4565      /**
4566       * @return the length of the stack
4567       */
4568      public int getStackLength() {
4569        return stack.length;
4570      }
4571    
4572      /**
4573       * @return the stack
4574       */
4575      public byte[] getStack() {
4576        return stack;
4577      }
4578    
4579      /**
4580       * @return the thread's exception registers
4581       */
4582      public Registers getExceptionRegisters() {
4583        return exceptionRegisters;
4584      }
4585    
4586      /**
4587       * @return the thread's context registers (saved registers when thread is
4588       *         suspended by green-thread scheduler).
4589       */
4590      public Registers getContextRegisters() {
4591        return contextRegisters;
4592      }
4593    
4594      /** Set the initial attempt. */
4595      public void reportCollectionAttempt() {
4596        collectionAttempt++;
4597      }
4598    
4599      /** Set the initial attempt. */
4600      public int getCollectionAttempt() {
4601        return collectionAttempt;
4602      }
4603    
4604      /** Resets the attempts. */
4605      public void resetCollectionAttempts() {
4606        collectionAttempt = 0;
4607      }
4608    
4609      /** Get the physical allocation failed flag. */
4610      public boolean physicalAllocationFailed() {
4611        return physicalAllocationFailed;
4612      }
4613    
4614      /** Set the physical allocation failed flag. */
4615      public void setPhysicalAllocationFailed() {
4616        physicalAllocationFailed = true;
4617      }
4618    
4619      /** Clear the physical allocation failed flag. */
4620      public void clearPhysicalAllocationFailed() {
4621        physicalAllocationFailed = false;
4622      }
4623    
4624      /**
4625       * Returns the outstanding OutOfMemoryError.
4626       */
4627      public static OutOfMemoryError getOutOfMemoryError() {
4628        return outOfMemoryError;
4629      }
4630    
4631      /**
4632       * Number of active threads in the system.
4633       */
4634      public static int getNumActiveThreads() {
4635        return numActiveThreads;
4636      }
4637    
4638      /**
4639       * Number of active daemon threads.
4640       */
4641      public static int getNumActiveDaemons() {
4642        return numActiveDaemons;
4643      }
4644    
4645      @Interruptible
4646      public void handleUncaughtException(Throwable exceptionObject) {
4647        uncaughtExceptionCount++;
4648    
4649        handlePossibleRecursiveException();
4650        VM.enableGC();
4651        if (thread == null) {
4652          VM.sysWrite("Exception in the primordial thread \"", getName(),
4653              "\" while booting: ");
4654        } else {
4655          // This is output like that of the Sun JDK.
4656          VM.sysWrite("Exception in thread \"", getName(), "\": ");
4657        }
4658        if (exceptionObject instanceof OutOfMemoryError) {
4659          VM.sysWriteln("   <<No stacktrace available>>");
4660        } else if (VM.fullyBooted) {
4661          exceptionObject.printStackTrace();
4662        }
4663        getCurrentThread().terminate();
4664        if (VM.VerifyAssertions)
4665          VM._assert(VM.NOT_REACHED);
4666      }
4667    
4668      /** Handle the case of exception handling triggering new exceptions. */
4669      private void handlePossibleRecursiveException() {
4670        if (uncaughtExceptionCount > 1 &&
4671            uncaughtExceptionCount <= VM.maxSystemTroubleRecursionDepth + VM.maxSystemTroubleRecursionDepthBeforeWeStopVMSysWrite) {
4672          VM.sysWrite("We got an uncaught exception while (recursively) handling ");
4673          VM.sysWrite(uncaughtExceptionCount - 1);
4674          VM.sysWrite(" uncaught exception");
4675          if (uncaughtExceptionCount - 1 != 1) {
4676            VM.sysWrite("s");
4677          }
4678          VM.sysWriteln(".");
4679        }
4680        if (uncaughtExceptionCount > VM.maxSystemTroubleRecursionDepth) {
4681          dumpVirtualMachine();
4682          VM.dieAbruptlyRecursiveSystemTrouble();
4683          if (VM.VerifyAssertions)
4684            VM._assert(VM.NOT_REACHED);
4685        }
4686      }
4687    
4688      private static void dumpThread(RVMThread t) {
4689        if (t == null) {
4690          VM.sysWrite("none");
4691        } else {
4692          VM.sysWrite(t.threadSlot, "(", t.getExecStatus());
4693          if (t.isAboutToTerminate) {
4694            VM.sysWrite("T");
4695          }
4696          if (t.isBlocking) {
4697            VM.sysWrite("B");
4698          }
4699          if (t.isJoinable) {
4700            VM.sysWrite("J");
4701          }
4702          if (t.atYieldpoint) {
4703            VM.sysWrite("Y");
4704          }
4705          VM.sysWrite(")");
4706        }
4707      }
4708    
4709      private static void dumpThreadArray(RVMThread[] array, int bound) {
4710        for (int i = 0; i < bound; ++i) {
4711          if (i != 0) {
4712            VM.sysWrite(", ");
4713          }
4714          VM.sysWrite(i, ":");
4715          dumpThread(array[i]);
4716        }
4717      }
4718    
4719      private static void dumpThreadSlotArray(int[] array, int bound) {
4720        for (int i = 0; i < bound; ++i) {
4721          if (i != 0) {
4722            VM.sysWrite(", ");
4723          }
4724          VM.sysWrite(i, ":");
4725          int threadSlot=array[i];
4726          VM.sysWrite(threadSlot, ",");
4727          dumpThread(threadBySlot[array[i]]);
4728        }
4729      }
4730    
4731      private static void dumpThreadArray(String name, RVMThread[] array, int bound) {
4732        VM.sysWrite(name);
4733        VM.sysWrite(": ");
4734        dumpThreadArray(array, bound);
4735        VM.sysWriteln();
4736      }
4737    
4738      private static void dumpThreadSlotArray(String name, int[] array, int bound) {
4739        VM.sysWrite(name);
4740        VM.sysWrite(": ");
4741        dumpThreadSlotArray(array, bound);
4742        VM.sysWriteln();
4743      }
4744    
4745      public static void dumpAcct() {
4746        acctLock.lockNoHandshake();
4747        dumpLock.lockNoHandshake();
4748        VM.sysWriteln("====== Begin Thread Accounting Dump ======");
4749        dumpThreadArray("threadBySlot", threadBySlot, nextSlot);
4750        dumpThreadSlotArray("aboutToTerminate", aboutToTerminate, aboutToTerminateN);
4751        VM.sysWrite("freeSlots: ");
4752        for (int i = 0; i < freeSlotN; ++i) {
4753          if (i != 0) {
4754            VM.sysWrite(", ");
4755          }
4756          VM.sysWrite(i, ":", freeSlots[i]);
4757        }
4758        VM.sysWriteln();
4759        dumpThreadArray("threads", threads, numThreads);
4760        VM.sysWriteln("====== End Thread Accounting Dump ======");
4761        dumpLock.unlock();
4762        acctLock.unlock();
4763      }
4764    
4765      public void extDump() {
4766        dump();
4767        VM.sysWriteln();
4768        VM.sysWriteln("acquireCount for my monitor: ", monitor().acquireCount);
4769        VM.sysWriteln("yieldpoints taken: ", yieldpointsTaken);
4770        VM.sysWriteln("yieldpoints taken fully: ", yieldpointsTakenFully);
4771        VM.sysWriteln("native entered blocked: ", nativeEnteredBlocked);
4772        VM.sysWriteln("JNI entered blocked: ", jniEnteredBlocked);
4773      }
4774    
4775      /**
4776       * Dump this thread's identifying information, for debugging, via
4777       * {@link VM#sysWrite(String)}. We do not use any spacing or newline
4778       * characters. Callers are responsible for space-separating or
4779       * newline-terminating output.
4780       */
4781      public void dump() {
4782        dump(0);
4783      }
4784    
4785      /**
4786       * Dump this thread's identifying information, for debugging, via
4787       * {@link VM#sysWrite(String)}. We pad to a minimum of leftJustify
4788       * characters. We do not use any spacing characters. Callers are responsible
4789       * for space-separating or newline-terminating output.
4790       *
4791       * @param leftJustify
4792       *          minimum number of characters emitted, with any extra characters
4793       *          being spaces.
4794       */
4795      public void dumpWithPadding(int leftJustify) {
4796        char[] buf = Services.grabDumpBuffer();
4797        int len = dump(buf);
4798        VM.sysWrite(buf, len);
4799        for (int i = leftJustify - len; i > 0; i--) {
4800          VM.sysWrite(" ");
4801        }
4802        Services.releaseDumpBuffer();
4803      }
4804    
4805      /**
4806       * Dump this thread's identifying information, for debugging, via
4807       * {@link VM#sysWrite(String)}. We do not use any spacing or newline
4808       * characters. Callers are responsible for space-separating or
4809       * newline-terminating output.
4810       *
4811       * This function avoids write barriers and allocation.
4812       *
4813       * @param verbosity
4814       *          Ignored.
4815       */
4816      public void dump(int verbosity) {
4817        char[] buf = Services.grabDumpBuffer();
4818        int len = dump(buf);
4819        VM.sysWrite(buf, len);
4820        Services.releaseDumpBuffer();
4821      }
4822    
4823      /**
4824       * Dump this thread's info, for debugging. Copy the info about it into a
4825       * destination char array. We do not use any spacing or newline characters.
4826       *
4827       * This function may be called during GC; it avoids write barriers and
4828       * allocation.
4829       *
4830       * For this reason, we do not throw an <code>IndexOutOfBoundsException</code>.
4831       *
4832       * @param dest
4833       *          char array to copy the source info into.
4834       * @param offset
4835       *          Offset into <code>dest</code> where we start copying
4836       *
4837       * @return 1 plus the index of the last character written. If we were to write
4838       *         zero characters (which we won't) then we would return
4839       *         <code>offset</code>. This is intended to represent the first
4840       *         unused position in the array <code>dest</code>. However, it also
4841       *         serves as a pseudo-overflow check: It may have the value
4842       *         <code>dest.length</code>, if the array <code>dest</code> was
4843       *         completely filled by the call, or it may have a value greater than
4844       *         <code>dest.length</code>, if the info needs more than
4845       *         <code>dest.length - offset</code> characters of space.
4846       *
4847       * -1 if <code>offset</code> is negative.
4848       */
4849      public int dump(char[] dest, int offset) {
4850        offset = Services.sprintf(dest, offset, getThreadSlot()); // id
4851        if (daemon) {
4852          offset = Services.sprintf(dest, offset, "-daemon"); // daemon thread?
4853        }
4854        if (isBootThread()) {
4855          offset = Services.sprintf(dest, offset, "-Boot"); // Boot (Primordial)
4856          // thread
4857        }
4858        if (isSystemThread()) {
4859          offset = Services.sprintf(dest, offset, "-system"); // System Thread
4860        }
4861        if (isMainThread()) {
4862          offset = Services.sprintf(dest, offset, "-main"); // Main Thread
4863        }
4864        if (isCollectorThread()) {
4865          offset = Services.sprintf(dest, offset, "-collector"); // gc thread?
4866        }
4867        offset = Services.sprintf(dest, offset, "-");
4868        offset = Services.sprintf(dest, offset, getExecStatus());
4869        offset = Services.sprintf(dest, offset, "-");
4870        offset = Services.sprintf(dest, offset, java.lang.JikesRVMSupport
4871            .getEnumName(waiting));
4872        if (hasInterrupt || asyncThrowable != null) {
4873          offset = Services.sprintf(dest, offset, "-interrupted");
4874        }
4875        if (isAboutToTerminate) {
4876          offset = Services.sprintf(dest, offset, "-terminating");
4877        }
4878        return offset;
4879      }
4880    
4881      /**
4882       * Dump this thread's info, for debugging. Copy the info about it into a
4883       * destination char array. We do not use any spacing or newline characters.
4884       * <p>
4885       * This is identical to calling {@link #dump(char[],int)} with an
4886       * <code>offset</code> of zero.
4887       */
4888      public int dump(char[] dest) {
4889        return dump(dest, 0);
4890      }
4891    
4892      /** Dump statistics gather on operations */
4893      static void dumpStats() {
4894        VM.sysWrite("FatLocks: ");
4895        VM.sysWrite(waitOperations);
4896        VM.sysWrite(" wait operations\n");
4897        VM.sysWrite("FatLocks: ");
4898        VM.sysWrite(timedWaitOperations);
4899        VM.sysWrite(" timed wait operations\n");
4900        VM.sysWrite("FatLocks: ");
4901        VM.sysWrite(notifyOperations);
4902        VM.sysWrite(" notify operations\n");
4903        VM.sysWrite("FatLocks: ");
4904        VM.sysWrite(notifyAllOperations);
4905      }
4906    
4907      /**
4908       * Print out message in format "[j] (cez#td) who: what", where: j = java
4909       * thread id z* = RVMThread.getCurrentThread().yieldpointsEnabledCount (0
4910       * means yieldpoints are enabled outside of the call to debug) t* =
4911       * numActiveThreads d* = numActiveDaemons * parenthetical values, printed only
4912       * if traceDetails = true)
4913       * <p>
4914       * We serialize against a mutex to avoid intermingling debug output from
4915       * multiple threads.
4916       */
4917      public static void trace(String who, String what) {
4918        outputLock.lockNoHandshake();
4919        VM.sysWrite("[");
4920        RVMThread t = getCurrentThread();
4921        t.dump();
4922        VM.sysWrite("] ");
4923        if (traceDetails) {
4924          VM.sysWrite("(");
4925          VM.sysWriteInt(numActiveDaemons);
4926          VM.sysWrite("/");
4927          VM.sysWriteInt(numActiveThreads);
4928          VM.sysWrite(") ");
4929        }
4930        VM.sysWrite(who);
4931        VM.sysWrite(": ");
4932        VM.sysWrite(what);
4933        VM.sysWrite("\n");
4934        outputLock.unlock();
4935      }
4936    
4937      /**
4938       * Print out message in format "p[j] (cez#td) who: what howmany", where: p =
4939       * processor id j = java thread id c* = java thread id of the owner of
4940       * threadCreationMutex (if any) e* = java thread id of the owner of
4941       * threadExecutionMutex (if any) t* = numActiveThreads d* = numActiveDaemons *
4942       * parenthetical values, printed only if traceDetails = true)
4943       * <p>
4944       * We serialize against a mutex to avoid intermingling debug output from
4945       * multiple threads.
4946       */
4947      public static void trace(String who, String what, int howmany) {
4948        _trace(who, what, howmany, false);
4949      }
4950    
4951      // same as trace, but prints integer value in hex
4952      //
4953      public static void traceHex(String who, String what, int howmany) {
4954        _trace(who, what, howmany, true);
4955      }
4956    
4957      public static void trace(String who, String what, Address addr) {
4958        outputLock.lockNoHandshake();
4959        VM.sysWrite("[");
4960        getCurrentThread().dump();
4961        VM.sysWrite("] ");
4962        if (traceDetails) {
4963          VM.sysWrite("(");
4964          VM.sysWriteInt(numActiveDaemons);
4965          VM.sysWrite("/");
4966          VM.sysWriteInt(numActiveThreads);
4967          VM.sysWrite(") ");
4968        }
4969        VM.sysWrite(who);
4970        VM.sysWrite(": ");
4971        VM.sysWrite(what);
4972        VM.sysWrite(" ");
4973        VM.sysWriteHex(addr);
4974        VM.sysWrite("\n");
4975        outputLock.unlock();
4976      }
4977    
4978      private static void _trace(String who, String what, int howmany, boolean hex) {
4979        outputLock.lockNoHandshake();
4980        VM.sysWrite("[");
4981        // VM.sysWriteInt(RVMThread.getCurrentThread().getThreadSlot());
4982        getCurrentThread().dump();
4983        VM.sysWrite("] ");
4984        if (traceDetails) {
4985          VM.sysWrite("(");
4986          VM.sysWriteInt(numActiveDaemons);
4987          VM.sysWrite("/");
4988          VM.sysWriteInt(numActiveThreads);
4989          VM.sysWrite(") ");
4990        }
4991        VM.sysWrite(who);
4992        VM.sysWrite(": ");
4993        VM.sysWrite(what);
4994        VM.sysWrite(" ");
4995        if (hex) {
4996          VM.sysWriteHex(howmany);
4997        } else {
4998          VM.sysWriteInt(howmany);
4999        }
5000        VM.sysWrite("\n");
5001        outputLock.unlock();
5002      }
5003    
5004      /**
5005       * Print interesting scheduler information, starting with a stack traceback.
5006       * <p>
5007       * Note: the system could be in a fragile state when this method is called, so
5008       * we try to rely on as little runtime functionality as possible (eg. use no
5009       * bytecodes that require RuntimeEntrypoints support).
5010       */
5011      public static void traceback(String message) {
5012        if (VM.runningVM) {
5013          outputLock.lockNoHandshake();
5014        }
5015        VM.sysWriteln(message);
5016        tracebackWithoutLock();
5017        if (VM.runningVM) {
5018          outputLock.unlock();
5019        }
5020      }
5021    
5022      public static void traceback(String message, int number) {
5023        if (VM.runningVM) {
5024          outputLock.lockNoHandshake();
5025        }
5026        VM.sysWriteln(message, number);
5027        tracebackWithoutLock();
5028        if (VM.runningVM) {
5029          outputLock.unlock();
5030        }
5031      }
5032    
5033      static void tracebackWithoutLock() {
5034        if (VM.runningVM) {
5035          VM.sysWriteln("Thread #", getCurrentThreadSlot());
5036          dumpStack(Magic.getCallerFramePointer(Magic.getFramePointer()));
5037        } else {
5038          dumpStack();
5039        }
5040      }
5041    
5042      /**
5043       * Dump stack of calling thread, starting at callers frame
5044       */
5045      @UninterruptibleNoWarn("Never blocks")
5046      public static void dumpStack() {
5047        if (VM.runningVM) {
5048          VM.sysWriteln("Dumping stack for Thread #", getCurrentThreadSlot());
5049          dumpStack(Magic.getFramePointer());
5050        } else {
5051          StackTraceElement[] elements = (new Throwable(
5052              "--traceback from Jikes RVM's RVMThread class--")).getStackTrace();
5053          for (StackTraceElement element : elements) {
5054            System.err.println(element.toString());
5055          }
5056        }
5057      }
5058    
5059      /**
5060       * Dump state of a (stopped) thread's stack.
5061       *
5062       * @param fp address of starting frame. first frame output is the calling
5063       * frame of passed frame
5064       */
5065      public static void dumpStack(Address fp) {
5066        if (VM.VerifyAssertions) {
5067          VM._assert(VM.runningVM);
5068        }
5069        Address ip = Magic.getReturnAddress(fp);
5070        fp = Magic.getCallerFramePointer(fp);
5071        dumpStack(ip, fp);
5072      }
5073    
5074      /**
5075       * Dump state of a (stopped) thread's stack.
5076       *
5077       * @param ip instruction pointer for first frame to dump
5078       * @param fp frame pointer for first frame to dump
5079       */
5080      public static void dumpStack(Address ip, Address fp) {
5081        boolean b = Monitor.lockNoHandshake(dumpLock);
5082        RVMThread t = getCurrentThread();
5083        ++t.inDumpStack;
5084        if (t.inDumpStack > 1 &&
5085            t.inDumpStack <= VM.maxSystemTroubleRecursionDepth + VM.maxSystemTroubleRecursionDepthBeforeWeStopVMSysWrite) {
5086          VM.sysWrite("RVMThread.dumpStack(): in a recursive call, ");
5087          VM.sysWrite(t.inDumpStack);
5088          VM.sysWriteln(" deep.");
5089        }
5090        if (t.inDumpStack > VM.maxSystemTroubleRecursionDepth) {
5091          VM.dieAbruptlyRecursiveSystemTrouble();
5092          if (VM.VerifyAssertions)
5093            VM._assert(VM.NOT_REACHED);
5094        }
5095    
5096        if (!isAddressValidFramePointer(fp)) {
5097          VM.sysWrite("Bogus looking frame pointer: ", fp);
5098          VM.sysWriteln(" not dumping stack");
5099        } else {
5100          try {
5101            VM.sysWriteln("-- Stack --");
5102            while (Magic.getCallerFramePointer(fp).NE(
5103                StackframeLayoutConstants.STACKFRAME_SENTINEL_FP)) {
5104    
5105              // if code is outside of RVM heap, assume it to be native code,
5106              // skip to next frame
5107              if (!MemoryManager.addressInVM(ip)) {
5108                showMethod("native frame", fp);
5109                ip = Magic.getReturnAddress(fp);
5110                fp = Magic.getCallerFramePointer(fp);
5111              } else {
5112    
5113                int compiledMethodId = Magic.getCompiledMethodID(fp);
5114                VM.sysWrite("("); VM.sysWrite(fp); VM.sysWrite(" "); VM.sysWrite(compiledMethodId); VM.sysWrite(")");
5115                if (compiledMethodId == StackframeLayoutConstants.INVISIBLE_METHOD_ID) {
5116                  showMethod("invisible method", fp);
5117                } else {
5118                  // normal java frame(s)
5119                  CompiledMethod compiledMethod = CompiledMethods
5120                      .getCompiledMethod(compiledMethodId);
5121                  if (compiledMethod == null) {
5122                    showMethod(compiledMethodId, fp);
5123                  } else if (compiledMethod.getCompilerType() == CompiledMethod.TRAP) {
5124                    showMethod("hardware trap", fp);
5125                  } else {
5126                    RVMMethod method = compiledMethod.getMethod();
5127                    Offset instructionOffset = compiledMethod
5128                        .getInstructionOffset(ip);
5129                    int lineNumber = compiledMethod
5130                        .findLineNumberForInstruction(instructionOffset);
5131                    boolean frameShown = false;
5132                    if (VM.BuildForOptCompiler && compiledMethod.getCompilerType() == CompiledMethod.OPT) {
5133                      OptCompiledMethod optInfo = (OptCompiledMethod) compiledMethod;
5134                      // Opt stack frames may contain multiple inlined methods.
5135                      OptMachineCodeMap map = optInfo.getMCMap();
5136                      int iei = map.getInlineEncodingForMCOffset(instructionOffset);
5137                      if (iei >= 0) {
5138                        int[] inlineEncoding = map.inlineEncoding;
5139                        int bci = map.getBytecodeIndexForMCOffset(instructionOffset);
5140                        for (; iei >= 0; iei = OptEncodedCallSiteTree.getParent(iei, inlineEncoding)) {
5141                          int mid = OptEncodedCallSiteTree.getMethodID(iei, inlineEncoding);
5142                          method = MemberReference.getMemberRef(mid).asMethodReference().getResolvedMember();
5143                          lineNumber = ((NormalMethod) method).getLineNumberForBCIndex(bci);
5144                          showMethod(method, lineNumber, fp);
5145                          if (iei > 0) {
5146                            bci = OptEncodedCallSiteTree.getByteCodeOffset(iei, inlineEncoding);
5147                          }
5148                        }
5149                        frameShown = true;
5150                      }
5151                    }
5152                    if (!frameShown) {
5153                      showMethod(method, lineNumber, fp);
5154                    }
5155                  }
5156                }
5157                ip = Magic.getReturnAddress(fp);
5158                fp = Magic.getCallerFramePointer(fp);
5159              }
5160              if (!isAddressValidFramePointer(fp)) {
5161                VM.sysWrite("Bogus looking frame pointer: ", fp);
5162                VM.sysWriteln(" end of stack dump");
5163                break;
5164              }
5165            } // end while
5166          } catch (Throwable th) {
5167            VM.sysWriteln("Something bad killed the stack dump. The last frame pointer was: ", fp);
5168          }
5169        }
5170        --t.inDumpStack;
5171    
5172        Monitor.unlock(b, dumpLock);
5173      }
5174    
5175      /**
5176       * Return true if the supplied address could be a valid frame pointer. To
5177       * check for validity we make sure the frame pointer is in one of the spaces;
5178       * <ul>
5179       * <li>LOS (For regular threads)</li>
5180       * <li>Immortal (For threads allocated in immortal space such as collectors)</li>
5181       * <li>Boot (For the boot thread)</li>
5182       * </ul>
5183       *
5184       * <p>
5185       * or it is {@link StackframeLayoutConstants#STACKFRAME_SENTINEL_FP}. The
5186       * STACKFRAME_SENTINEL_FP is possible when the thread has been created but has
5187       * yet to be scheduled.
5188       * </p>
5189       *
5190       * @param address
5191       *          the address.
5192       * @return true if the address could be a frame pointer, false otherwise.
5193       */
5194      private static boolean isAddressValidFramePointer(final Address address) {
5195        if (address.EQ(Address.zero()))
5196          return false; // Avoid hitting assertion failure in MMTk
5197        else
5198          return address.EQ(StackframeLayoutConstants.STACKFRAME_SENTINEL_FP) || MemoryManager.mightBeFP(address);
5199      }
5200    
5201      private static void showPrologue(Address fp) {
5202        VM.sysWrite("   at ");
5203        if (SHOW_FP_IN_STACK_DUMP) {
5204          VM.sysWrite("[");
5205          VM.sysWrite(fp);
5206          VM.sysWrite(", ");
5207          VM.sysWrite(Magic.getReturnAddress(fp));
5208          VM.sysWrite("] ");
5209        }
5210      }
5211    
5212      /**
5213       * Show a method where getCompiledMethod returns null
5214       *
5215       * @param compiledMethodId
5216       * @param fp
5217       */
5218      private static void showMethod(int compiledMethodId, Address fp) {
5219        showPrologue(fp);
5220        VM.sysWrite(
5221            "<unprintable normal Java frame: CompiledMethods.getCompiledMethod(",
5222            compiledMethodId, ") returned null>\n");
5223      }
5224    
5225      /**
5226       * Show a method that we can't show (ie just a text description of the stack
5227       * frame
5228       *
5229       * @param name
5230       * @param fp
5231       */
5232      private static void showMethod(String name, Address fp) {
5233        showPrologue(fp);
5234        VM.sysWrite("<");
5235        VM.sysWrite(name);
5236        VM.sysWrite(">\n");
5237      }
5238    
5239      /**
5240       * Helper function for {@link #dumpStack(Address,Address)}. Print a stack
5241       * frame showing the method.
5242       */
5243      private static void showMethod(RVMMethod method, int lineNumber, Address fp) {
5244        showPrologue(fp);
5245        if (method == null) {
5246          VM.sysWrite("<unknown method>");
5247        } else {
5248          VM.sysWrite(method.getDeclaringClass().getDescriptor());
5249          VM.sysWrite(" ");
5250          VM.sysWrite(method.getName());
5251          VM.sysWrite(method.getDescriptor());
5252        }
5253        if (lineNumber > 0) {
5254          VM.sysWrite(" at line ");
5255          VM.sysWriteInt(lineNumber);
5256        }
5257        VM.sysWrite("\n");
5258      }
5259    
5260      /**
5261       * Dump state of a (stopped) thread's stack and exit the virtual machine.
5262       *
5263       * @param fp
5264       *          address of starting frame Returned: doesn't return. This method is
5265       *          called from RunBootImage.C when something goes horrifically wrong
5266       *          with exception handling and we want to die with useful
5267       *          diagnostics.
5268       */
5269      @Entrypoint
5270      public static void dumpStackAndDie(Address fp) {
5271        if (!exitInProgress) {
5272          // This is the first time I've been called, attempt to exit "cleanly"
5273          exitInProgress = true;
5274          dumpStack(fp);
5275          VM.sysExit(VM.EXIT_STATUS_DUMP_STACK_AND_DIE);
5276        } else {
5277          // Another failure occurred while attempting to exit cleanly.
5278          // Get out quick and dirty to avoid hanging.
5279          sysCall.sysExit(VM.EXIT_STATUS_RECURSIVELY_SHUTTING_DOWN);
5280        }
5281      }
5282    
5283      /**
5284       * Is it safe to start forcing garbage collects for stress testing?
5285       */
5286      public static boolean safeToForceGCs() {
5287        return gcEnabled();
5288      }
5289    
5290      /**
5291       * Is it safe to start forcing garbage collects for stress testing?
5292       */
5293      public static boolean gcEnabled() {
5294        return threadingInitialized && getCurrentThread().yieldpointsEnabled();
5295      }
5296    
5297      /**
5298       * Set up the initial thread and processors as part of boot image writing
5299       *
5300       * @return the boot thread
5301       */
5302      @Interruptible
5303      public static RVMThread setupBootThread() {
5304        if (VM.VerifyAssertions) VM._assert(bootThread == null);
5305        BootThread bt = new BootThread();
5306        bootThread = bt.getRVMThread();
5307        bootThread.feedlet = TraceEngine.engine.makeFeedlet(
5308            "Jikes RVM boot thread",
5309            "Thread used to execute the initial boot sequence of Jikes RVM");
5310        numActiveThreads++;
5311        numActiveDaemons++;
5312        return bootThread;
5313      }
5314    
5315      /**
5316       * Dump state of virtual machine.
5317       */
5318      public static void dumpVirtualMachine() {
5319        boolean b = Monitor.lockNoHandshake(dumpLock);
5320        getCurrentThread().disableYieldpoints();
5321        VM.sysWrite("\n-- Threads --\n");
5322        for (int i = 0; i < numThreads; ++i) {
5323          RVMThread t = threads[i];
5324          if (t != null) {
5325            t.dumpWithPadding(30);
5326            VM.sysWrite("\n");
5327          }
5328        }
5329        VM.sysWrite("\n");
5330    
5331        VM.sysWrite("\n-- Locks in use --\n");
5332        Lock.dumpLocks();
5333    
5334        VM.sysWriteln("Dumping stack of active thread\n");
5335        dumpStack();
5336    
5337        VM.sysWriteln("Attempting to dump the stack of all other live threads");
5338        VM.sysWriteln("This is somewhat risky since if the thread is running we're going to be quite confused");
5339        for (int i = 0; i < numThreads; ++i) {
5340          RVMThread thr = threads[i];
5341          if (thr != null && thr != RVMThread.getCurrentThread() && thr.isAlive()) {
5342            thr.dump();
5343            // PNT: FIXME: this won't work so well since the context registers
5344            // don't tend to have sane values
5345            if (thr.contextRegisters != null && !thr.ignoreHandshakesAndGC())
5346              dumpStack(thr.contextRegisters.getInnermostFramePointer());
5347          }
5348        }
5349        getCurrentThread().enableYieldpoints();
5350        Monitor.unlock(b, dumpLock);
5351      }
5352    
5353      public static Feedlet getCurrentFeedlet() {
5354        return getCurrentThread().feedlet;
5355      }
5356    
5357      ////////////////////////// VM.countThreadTransitions support //////////////////////////
5358    
5359      static final int[] sloppyExecStatusHistogram =
5360        new int[LAST_EXEC_STATUS];
5361      static final int[] statusAtSTWHistogram =
5362        new int[LAST_EXEC_STATUS];
5363      static final int[] execStatusTransitionHistogram =
5364        new int[LAST_EXEC_STATUS*LAST_EXEC_STATUS];
5365    
5366      public static void reportThreadTransitionCounts() {
5367        VM.sysWriteln("Thread Transition Counts:");
5368        dump1DHisto("Sloppy Exec Status Histogram",sloppyExecStatusHistogram);
5369        dump1DHisto("Status At Stop-the-world Histogram",statusAtSTWHistogram);
5370        VM.sysWriteln("  Exec Status Transition Histogram:");
5371        for (int fromI=0;fromI<LAST_EXEC_STATUS;++fromI) {
5372          for (int toI=0;toI<LAST_EXEC_STATUS;++toI) {
5373            int val=
5374              execStatusTransitionHistogram[
5375                transitionHistogramIndex(fromI,toI)];
5376            if (val!=0) {
5377              VM.sysWriteln("    ",fromI,"->",toI," ",val);
5378            }
5379          }
5380        }
5381      }
5382    
5383      static void dump1DHisto(String name,int[] histo) {
5384        VM.sysWriteln("  ",name,":");
5385        for (int i=0;i<LAST_EXEC_STATUS;++i) {
5386          if (histo[i]!=0) {
5387            VM.sysWriteln("    ",i," ",histo[i]);
5388          }
5389        }
5390      }
5391    
5392      void observeExecStatus() {
5393        sloppyExecStatusHistogram[execStatus]++;
5394      }
5395    
5396      public static void observeExecStatusAtSTW(int execStatus) {
5397        statusAtSTWHistogram[execStatus]++;
5398      }
5399    
5400      // FIXME: add histograms for states returned from various calls to block()
5401      // currently we just do it for the block() call in GC STW.
5402    
5403      static int transitionHistogramIndex(int oldState,int newState) {
5404        return oldState+newState*LAST_EXEC_STATUS;
5405      }
5406    
5407      static void observeStateTransition(int oldState,int newState) {
5408        execStatusTransitionHistogram[transitionHistogramIndex(oldState,newState)]++;
5409        sloppyExecStatusHistogram[oldState]++;
5410        sloppyExecStatusHistogram[newState]++;
5411      }
5412    }