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