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