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