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