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.mm.mmtk; 014 015import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS; 016 017import org.jikesrvm.VM; 018import org.jikesrvm.architecture.AbstractRegisters; 019import org.jikesrvm.architecture.StackFrameLayout; 020import org.jikesrvm.classloader.RVMMethod; 021import org.jikesrvm.compilers.common.CompiledMethod; 022import org.jikesrvm.compilers.common.CompiledMethods; 023import org.jikesrvm.mm.mminterface.DebugUtil; 024import org.jikesrvm.mm.mminterface.GCMapIterator; 025import org.jikesrvm.mm.mminterface.GCMapIteratorGroup; 026import org.jikesrvm.mm.mminterface.MemoryManager; 027import org.jikesrvm.mm.mminterface.Selected; 028import org.jikesrvm.runtime.Magic; 029import org.jikesrvm.runtime.RuntimeEntrypoints; 030import org.jikesrvm.scheduler.RVMThread; 031import org.mmtk.plan.TraceLocal; 032import org.mmtk.utility.Log; 033import org.mmtk.utility.options.Options; 034import org.vmmagic.pragma.Inline; 035import org.vmmagic.pragma.Uninterruptible; 036import org.vmmagic.pragma.Untraced; 037import org.vmmagic.unboxed.Address; 038import org.vmmagic.unboxed.ObjectReference; 039import org.vmmagic.unboxed.Offset; 040 041/** 042 * Class that supports scanning thread stacks for references during 043 * collections. References are located using GCMapIterators and are 044 * inserted into a set of root locations. Optionally, a set of 045 * interior pointer locations associated with the object is created.<p> 046 * 047 * Threads, stacks, jni environments, and register objects have a 048 * complex interaction in terms of scanning. The operation of 049 * scanning the stack reveals not only roots inside the stack but also 050 * the state of the register objects's gprs and the JNI refs array. 051 * They are all associated via the thread object, making it natural 052 * for scanThread to be considered a single operation with the method 053 * directly accessing these objects via the thread object's 054 * fields. <p> 055 * 056 * One pitfall occurs when scanning the thread object (plus 057 * dependents) when not all of the objects have been copied. Then it 058 * may be that the innards of the register object has not been copied 059 * while the stack object has. The result is that an inconsistent set 060 * of slots is reported. In this case, the copied register object may 061 * not be correct if the copy occurs after the root locations are 062 * discovered but before those locations are processed. In essence, 063 * all of these objects form one logical unit but are physically 064 * separated so that sometimes only part of it has been copied causing 065 * the scan to be incorrect. <p> 066 * 067 * The caller of the stack scanning routine must ensure that all of 068 * these components's descendants are consistent (all copied) when 069 * this method is called. <p> 070 * 071 * <i>Code locations:</i> Identifying pointers <i>into</i> code 072 * objects is essential if code objects are allowed to move (and if 073 * the code objects were not otherwise kept alive, it would be 074 * necessary to ensure the liveness of the code objects). A code 075 * pointer is the only case in which we have interior pointers 076 * (pointers into the inside of objects). For such pointers, two 077 * things must occur: first the pointed to object must be kept alive, 078 * and second, if the pointed to object is moved by a copying 079 * collector, the pointer into the object must be adjusted so it now 080 * points into the newly copied object 081 */ 082@Uninterruptible public final class ScanThread { 083 084 /*********************************************************************** 085 * 086 * Class variables 087 */ 088 089 /** quietly validates each ref reported by map iterators */ 090 static final boolean VALIDATE_REFS = VM.VerifyAssertions; 091 092 /* 093 * debugging options to produce printout during scanStack 094 * MULTIPLE GC THREADS WILL PRODUCE SCRAMBLED OUTPUT so only 095 * use these when running with PROCESSORS=1 096 */ 097 private static final int DEFAULT_VERBOSITY = 0 /*0*/; 098 private static final int FAILURE_VERBOSITY = 4; 099 100 /*********************************************************************** 101 * 102 * Instance variables 103 */ 104 105 /** 106 * 107 */ 108 private final GCMapIteratorGroup iteratorGroup = new GCMapIteratorGroup(); 109 @Untraced 110 private GCMapIterator iterator; 111 @Untraced 112 private TraceLocal trace; 113 private boolean processCodeLocations; 114 @Untraced 115 private RVMThread thread; 116 private Address ip, fp, prevFp, initialIPLoc, topFrame; 117 @Untraced 118 private CompiledMethod compiledMethod; 119 private int compiledMethodType; 120 private boolean failed; 121 private boolean reinstallReturnBarrier; 122 123 /*********************************************************************** 124 * 125 * Thread scanning 126 */ 127 128 /** 129 * Scan a thread, placing the addresses of pointers into supplied buffers. 130 * 131 * @param thread The thread to be scanned 132 * @param trace The trace instance to use for reporting references. 133 * @param processCodeLocations Should code locations be processed? 134 * @param newRootsSufficient Is a partial stack scan sufficient, or must we do a full scan? 135 */ 136 public static void scanThread(RVMThread thread, TraceLocal trace, 137 boolean processCodeLocations, boolean newRootsSufficient) { 138 if (DEFAULT_VERBOSITY >= 1) { 139 VM.sysWriteln("scanning ",thread.getThreadSlot()); 140 } 141 142 /* get the gprs associated with this thread */ 143 AbstractRegisters regs = thread.getContextRegisters(); 144 Address gprs = Magic.objectAsAddress(regs.getGPRs()); 145 146 Address ip = regs.getInnermostInstructionAddress(); 147 Address fp = regs.getInnermostFramePointer(); 148 regs.clear(); 149 regs.setInnermost(ip,fp); 150 151 scanThread(thread, trace, processCodeLocations, gprs, Address.zero(), newRootsSufficient); 152 } 153 154 /** 155 * Wrapper for {@link TraceLocal#reportDelayedRootEdge(Address)} that allows 156 * sanity checking of the address. 157 * 158 * @param trace the trace on which {@link TraceLocal#reportDelayedRootEdge(Address)} 159 * will be called 160 * @param addr see JavaDoc of {@link TraceLocal#reportDelayedRootEdge(Address)} 161 */ 162 private static void reportDelayedRootEdge(TraceLocal trace, Address addr) { 163 if (VALIDATE_REFS) checkReference(addr); 164 trace.reportDelayedRootEdge(addr); 165 } 166 167 /** 168 * A more general interface to thread scanning, which permits the 169 * scanning of stack segments which are dislocated from the thread 170 * structure. 171 * 172 * @param thread The thread to be scanned 173 * @param trace The trace instance to use for reporting references. 174 * @param processCodeLocations Should code locations be processed? 175 * @param gprs The general purpose registers associated with the 176 * stack being scanned (normally extracted from the thread). 177 * @param topFrame The top frame of the stack being scanned, or zero 178 * if this is to be inferred from the thread (normally the case). 179 * @param newRootsSufficent Is a partial stack scan sufficient, or must we do a full scan? 180 */ 181 private static void scanThread(RVMThread thread, TraceLocal trace, 182 boolean processCodeLocations, 183 Address gprs, Address topFrame, boolean newRootsSufficent) { 184 // figure out if the thread should be scanned at all; if not, exit 185 if (thread.getExecStatus() == RVMThread.NEW || thread.getIsAboutToTerminate()) { 186 return; 187 } 188 /* establish ip and fp for the stack to be scanned */ 189 Address ip, fp, initialIPLoc; 190 if (topFrame.isZero()) { /* implicit top of stack, inferred from thread */ 191 ip = thread.getContextRegisters().getInnermostInstructionAddress(); 192 fp = thread.getContextRegisters().getInnermostFramePointer(); 193 initialIPLoc = thread.getContextRegisters().getIPLocation(); 194 } else { /* top frame explicitly defined */ 195 ip = Magic.getReturnAddress(topFrame, thread); 196 fp = Magic.getCallerFramePointer(topFrame); 197 initialIPLoc = thread.getContextRegisters().getIPLocation(); // FIXME 198 } 199 200 /* Grab the ScanThread instance associated with this thread */ 201 ScanThread scanner = RVMThread.getCurrentThread().getCollectorThread().getThreadScanner(); 202 203 /* Expicitly establish the stopping point for this scan (not necessarily the bottom of stack) */ 204 Address sentinalFp = newRootsSufficent && Options.useShortStackScans.getValue() ? thread.getNextUnencounteredFrame() : StackFrameLayout.getStackFrameSentinelFP(); 205 206 /* stack trampoline will be freshly reinstalled at end of thread scan */ 207 if (Options.useReturnBarrier.getValue() || Options.useShortStackScans.getValue()) { 208 thread.deInstallStackTrampoline(); 209 } 210 211 /* scan the stack */ 212 scanner.startScan(trace, processCodeLocations, thread, gprs, ip, fp, initialIPLoc, topFrame, sentinalFp); 213 } 214 215 /** 216 * Initializes a ScanThread instance, and then scans a stack 217 * associated with a thread, and places references in deques (one for 218 * object pointers, one for interior code pointers). If the thread 219 * scan fails, the thread is rescanned verbosely and a failure 220 * occurs.<p> 221 * 222 * The various state associated with stack scanning is captured by 223 * instance variables of this type, which are initialized here. 224 * 225 * @param trace The trace instance to use for reporting locations. 226 * @param processCodeLocations whether to process parts of the thread 227 * that could point to code (e.g. exception registers). 228 * @param thread Thread for the thread whose stack is being scanned 229 * @param gprs The general purpose registers associated with the 230 * stack being scanned (normally extracted from the thread). 231 * @param ip The instruction pointer for the top frame of the stack 232 * we're about to scan. 233 * @param fp The frame pointer for the top frame of the stack we're 234 * about to scan. 235 * @param initialIPLoc the address of the initial location of the instruction 236 * pointer 237 * @param topFrame The top frame of the stack being scanned, or zero 238 * if this is to be inferred from the thread (normally the case). 239 * @param sentinelFp The frame pointer at which the stack scan should stop. 240 */ 241 private void startScan(TraceLocal trace, 242 boolean processCodeLocations, 243 RVMThread thread, Address gprs, Address ip, 244 Address fp, Address initialIPLoc, Address topFrame, 245 Address sentinelFp) { 246 this.trace = trace; 247 this.processCodeLocations = processCodeLocations; 248 this.thread = thread; 249 this.failed = false; 250 this.ip = ip; 251 this.fp = fp; 252 this.initialIPLoc = initialIPLoc; 253 this.topFrame = topFrame; 254 scanThreadInternal(gprs, DEFAULT_VERBOSITY, sentinelFp); 255 if (failed) { 256 /* reinitialize and rescan verbosely on failure */ 257 this.ip = ip; 258 this.fp = fp; 259 this.topFrame = topFrame; 260 scanThreadInternal(gprs, FAILURE_VERBOSITY, sentinelFp); 261 VM.sysFail("Error encountered while scanning stack"); 262 } 263 } 264 265 /** 266 * The main stack scanning loop.<p> 267 * 268 * Walk the stack one frame at a time, top (lo) to bottom (hi),<p> 269 * 270 * @param gprs The general purpose registers associated with the 271 * stack being scanned (normally extracted from the thread). 272 * @param verbosity The level of verbosity to be used when 273 * performing the scan. 274 * @param sentinelFp the frame pointer at which the stack scan should stop 275 */ 276 private void scanThreadInternal(Address gprs, int verbosity, Address sentinelFp) { 277 if (false) { 278 VM.sysWriteln("Scanning thread ",thread.getThreadSlot()," from thread ",RVMThread.getCurrentThreadSlot()); 279 } 280 if (verbosity >= 2) { 281 Log.writeln("--- Start Of Stack Scan ---\n"); 282 Log.write("Thread #"); 283 Log.writeln(thread.getThreadSlot()); 284 } 285 if (VM.VerifyAssertions) assertImmovableInCurrentCollection(); 286 287 /* first find any references to exception handlers in the registers */ 288 getHWExceptionRegisters(); 289 290 /* reinitialize the stack iterator group */ 291 iteratorGroup.newStackWalk(thread, gprs); 292 293 if (verbosity >= 2) dumpTopFrameInfo(verbosity); 294 295 /* scan each frame if a non-empty stack */ 296 if (fp.NE(StackFrameLayout.getStackFrameSentinelFP())) { 297 prevFp = Address.zero(); 298 reinstallReturnBarrier = Options.useReturnBarrier.getValue() || Options.useShortStackScans.getValue(); 299 /* At start of loop: 300 fp -> frame for method invocation being processed 301 ip -> instruction pointer in the method (normally a call site) */ 302 while (Magic.getCallerFramePointer(fp).NE(sentinelFp)) { 303 if (false) { 304 VM.sysWriteln("Thread ",RVMThread.getCurrentThreadSlot()," at fp = ",fp); 305 } 306 prevFp = scanFrame(verbosity); 307 ip = Magic.getReturnAddress(fp, thread); 308 fp = Magic.getCallerFramePointer(fp); 309 } 310 } 311 312 /* If a thread started via createVM or attachVM, base may need scaning */ 313 // TODO implement this if necessary. It was previously only implemented for 314 // AIX which is no longer supported. 315 316 if (verbosity >= 2) Log.writeln("--- End Of Stack Scan ---\n"); 317 } 318 319 /** 320 * When an exception occurs, registers are saved temporarily. If 321 * the stack being scanned is in this state, we need to scan those 322 * registers for code pointers. If the codeLocations deque is null, 323 * then scanning for code pointers is not required, so we don't need 324 * to do anything. (SB: Why only code pointers?). 325 * <p> 326 * Dave G: The contents of the GPRs of the exceptionRegisters 327 * are handled during normal stack scanning 328 * (@see org.jikesrvm.runtime.compilers.common.HardwareTrapCompiledMethod. 329 * It looks to me like the main goal of this method is to ensure that the 330 * method in which the trap happened isn't treated as dead code and collected 331 * (if it's been marked as obsolete, we are setting its activeOnStackFlag below). 332 */ 333 private void getHWExceptionRegisters() { 334 AbstractRegisters exReg = thread.getExceptionRegisters(); 335 if (processCodeLocations && exReg.getInUse()) { 336 Address ip = exReg.getIP(); 337 CompiledMethod compiledMethod = CompiledMethods.findMethodForInstruction(ip); 338 if (VM.VerifyAssertions) { 339 VM._assert(compiledMethod != null); 340 VM._assert(compiledMethod.containsReturnAddress(ip)); 341 } 342 compiledMethod.setActiveOnStack(); 343 ObjectReference code = ObjectReference.fromObject(compiledMethod.getEntryCodeArray()); 344 Address ipLoc = exReg.getIPLocation(); 345 if (VM.VerifyAssertions) VM._assert(ip.EQ(ipLoc.loadAddress())); 346 processCodeLocation(code, ipLoc); 347 } 348 } 349 350 /** 351 * Push a code pointer location onto the code locations deque, 352 * optionally performing a sanity check first.<p> 353 * 354 * @param code The code object into which this interior pointer points 355 * @param ipLoc The location of the pointer into this code object 356 */ 357 @Inline 358 private void processCodeLocation(ObjectReference code, Address ipLoc) { 359 if (VALIDATE_REFS) { 360 Address ip = ipLoc.loadAddress(); 361 Offset offset = ip.diff(code.toAddress()); 362 363 if (offset.sLT(Offset.zero()) || 364 offset.sGT(Offset.fromIntZeroExtend(ObjectModel.getObjectSize(code)))) { 365 Log.writeln("ERROR: Suspiciously large offset of interior pointer from object base"); 366 Log.write(" object base = "); Log.writeln(code); 367 Log.write(" interior reference = "); Log.writeln(ip); 368 Log.write(" offset = "); Log.writeln(offset); 369 Log.write(" interior ref loc = "); Log.writeln(ipLoc); 370 if (!failed) failed = true; 371 } 372 } 373 trace.processInteriorEdge(code, ipLoc, true); 374 } 375 376 /*********************************************************************** 377 * 378 * Frame scanning methods 379 */ 380 381 /** 382 * Scan the current stack frame.<p> 383 * 384 * First the various iterators are set up, then the frame is scanned 385 * for regular pointers, before scanning for code pointers. The 386 * iterators are then cleaned up, and native frames skipped if 387 * necessary. 388 * 389 * @param verbosity The level of verbosity to be used when 390 * performing the scan. 391 * @return the frame pointer of the frame that was just scanned 392 */ 393 private Address scanFrame(int verbosity) { 394 /* set up iterators etc, and skip the frame if appropriate */ 395 if (!setUpFrame(verbosity)) return fp; 396 397 /* scan the frame for object pointers */ 398 scanFrameForObjects(verbosity); 399 400 /* scan the frame for pointers to code */ 401 if (processCodeLocations && compiledMethodType != CompiledMethod.TRAP) 402 processFrameForCode(verbosity); 403 404 iterator.cleanupPointers(); 405 406 if (compiledMethodType != CompiledMethod.TRAP) { 407 /* skip preceding native frames if this frame is a native bridge */ 408 if (compiledMethod.getMethod().getDeclaringClass().hasBridgeFromNativeAnnotation()) { 409 fp = RuntimeEntrypoints.unwindNativeStackFrameForGC(fp); 410 if (verbosity >= 2) Log.write("scanFrame skipping native C frames\n"); 411 } 412 413 /* reinstall the return barrier if necessary (and verbosity indicates that this is a regular scan) */ 414 if (reinstallReturnBarrier && verbosity == DEFAULT_VERBOSITY) { 415 thread.installStackTrampolineBridge(fp); 416 reinstallReturnBarrier = false; 417 } 418 } 419 return fp; 420 } 421 422 /** 423 * Set up to scan the current stack frame. This means examining the 424 * frame to discover the method being invoked and then retrieving 425 * the associated metadata (stack maps etc). Certain frames should 426 * not be scanned---these are identified and skipped. 427 * 428 * @param verbosity The level of verbosity to be used when 429 * performing the scan. 430 * @return True if the frame should be scanned, false if it should 431 * be skipped. 432 */ 433 private boolean setUpFrame(int verbosity) { 434 /* get the compiled method ID for this frame */ 435 int compiledMethodId = Magic.getCompiledMethodID(fp); 436 437 /* skip "invisible" transition frames generated by reflection and JNI) */ 438 if (compiledMethodId == StackFrameLayout.getInvisibleMethodID()) { 439 if (verbosity >= 2) Log.writeln("\n--- METHOD <invisible method>"); 440 return false; 441 } 442 443 /* establish the compiled method */ 444 compiledMethod = CompiledMethods.getCompiledMethod(compiledMethodId); 445 compiledMethod.setActiveOnStack(); // prevents code from being collected 446 447 compiledMethodType = compiledMethod.getCompilerType(); 448 449 if (verbosity >= 2) printMethodHeader(); 450 451 /* get the code associated with this frame */ 452 if (RVMThread.DEBUG_STACK_TRAMPOLINE) VM.sysWriteln(thread.getId(), fp, compiledMethod.getMethod()); 453 Offset offset = compiledMethod.getInstructionOffset(ip); 454 455 /* initialize MapIterator for this frame */ 456 iterator = iteratorGroup.selectIterator(compiledMethod); 457 iterator.setupIterator(compiledMethod, offset, fp); 458 459 if (verbosity >= 3) dumpStackFrame(verbosity); 460 if (verbosity >= 4) Log.writeln("--- Refs Reported By GCMap Iterator ---"); 461 462 return true; 463 } 464 465 /** 466 * Identify all the object pointers stored as local variables 467 * associated with (though not necessarily strictly within!) the 468 * current frame. Loop through the GC map iterator, getting the 469 * address of each object pointer, adding them to the root locations 470 * deque.<p> 471 * 472 * NOTE: Because of the callee save policy of the optimizing 473 * compiler, references associated with a given frame may be in 474 * callee stack frames (lower memory), <i>outside</i> the current 475 * frame. So the iterator may return locations that are outside the 476 * frame being scanned. 477 * 478 * @param verbosity The level of verbosity to be used when 479 * performing the scan. 480 */ 481 private void scanFrameForObjects(int verbosity) { 482 for (Address refaddr = iterator.getNextReferenceAddress(); 483 !refaddr.isZero(); 484 refaddr = iterator.getNextReferenceAddress()) { 485 if (VALIDATE_REFS) checkReference(refaddr, verbosity); 486 if (verbosity >= 4) dumpRef(refaddr, verbosity); 487 reportDelayedRootEdge(trace, refaddr); 488 } 489 } 490 491 /** 492 * Identify all pointers into code pointers associated with a frame. 493 * There are two cases to be considered: a) the instruction pointer 494 * associated with each frame (stored in the thread's metadata for 495 * the top frame and as a return address for all subsequent frames), 496 * and b) local variables on the stack which happen to be pointers 497 * to code.<p> 498 * 499 * FIXME: SB: Why is it that JNI frames are skipped when considering 500 * top of stack frames, while boot image frames are skipped when 501 * considering other frames. Shouldn't they both be considered in 502 * both cases? 503 * 504 * @param verbosity The level of verbosity to be used when 505 * performing the scan. 506 */ 507 private void processFrameForCode(int verbosity) { 508 /* get the code object associated with this frame */ 509 ObjectReference code = ObjectReference.fromObject(compiledMethod.getEntryCodeArray()); 510 511 pushFrameIP(code, verbosity); 512 scanFrameForCode(code); 513 } 514 515 /** 516 * Push the instruction pointer associated with this frame onto the 517 * code locations deque.<p> 518 * 519 * A stack frame represents an execution context, and thus has an 520 * instruction pointer associated with it. In the case of the top 521 * frame, the instruction pointer is captured by the IP register, 522 * which is preserved in the thread data structure at thread switch 523 * time. In the case of all non-top frames, the next instruction 524 * pointer is stored as the return address for the <i>previous</i> 525 * frame.<p> 526 * 527 * The address of the code pointer is pushed onto the code locations 528 * deque along with the address of the code object into which it 529 * points (both are required since the former is an internal 530 * pointer).<p> 531 * 532 * The code pointers are updated later (after stack scanning) when 533 * the code locations deque is processed. The pointer from RVMMethod 534 * to the code object is not updated until after stack scanning, so 535 * the pointer to the (uncopied) code object is available throughout 536 * the stack scanning process, which enables interior pointer 537 * offsets to be correctly computed. 538 * 539 * @param code start address of the machine code array associated 540 * with the method 541 * @param verbosity The level of verbosity to be used when 542 * performing the scan. 543 */ 544 private void pushFrameIP(ObjectReference code, int verbosity) { 545 if (prevFp.isZero()) { /* top of stack: IP in thread state */ 546 if (verbosity >= 3) { 547 Log.write(" t.contextRegisters.ip = "); 548 Log.writeln(thread.getContextRegisters().getIP()); 549 Log.write("*t.contextRegisters.iploc = "); 550 Log.writeln(thread.getContextRegisters().getIPLocation().loadAddress()); 551 } 552 /* skip native code, as it is not (cannot be) moved */ 553 if (compiledMethodType != CompiledMethod.JNI) 554 processCodeLocation(code, initialIPLoc); 555 else if (verbosity >= 4) { 556 Log.writeln("GC Warning: SKIPPING return address for JNI code"); 557 } 558 } else { /* below top of stack: IP is return address, in prev frame */ 559 Address returnAddressLoc = Magic.getReturnAddressLocation(prevFp); 560 Address returnAddress = returnAddressLoc.loadAddress(); 561 if (verbosity >= 4) { 562 Log.write("--- Processing return address "); Log.write(returnAddress); 563 Log.write(" located at "); Log.writeln(returnAddressLoc); 564 } 565 /* skip boot image code, as it is not (cannot be) moved */ 566 if (!DebugUtil.addrInBootImage(returnAddress)) 567 processCodeLocation(code, returnAddressLoc); 568 } 569 } 570 571 /** 572 * Scan this frame for internal code pointers. The GC map iterator 573 * is used to identify any local variables (stored on the stack) 574 * which happen to be pointers into code.<p> 575 * 576 * @param code The code object associated with this frame. 577 */ 578 private void scanFrameForCode(ObjectReference code) { 579 iterator.reset(); 580 for (Address retaddrLoc = iterator.getNextReturnAddressAddress(); 581 !retaddrLoc.isZero(); 582 retaddrLoc = iterator.getNextReturnAddressAddress()) 583 processCodeLocation(code, retaddrLoc); 584 } 585 586 /*********************************************************************** 587 * 588 * Debugging etc 589 */ 590 591 /** 592 * Assert that the stack is immovable.<p> 593 * 594 * Currently we do not allow stacks to be moved within the heap. If 595 * a stack contains native stack frames, then it is impossible for 596 * us to safely move it. Prior to the implementation of JNI, Jikes 597 * RVM did allow the GC system to move thread stacks, and called a 598 * special fixup routine, thread.fixupMovedStack to adjust all of 599 * the special interior pointers (SP, FP). If we implement split C 600 * & Java stacks then we could allow the Java stacks to be moved, 601 * but we can't move the native stack. 602 */ 603 private void assertImmovableInCurrentCollection() { 604 // This method is guarded by VM.VerifyAssertions. Our Checkstyle assertion 605 // plugin does not recognize this because it does not track calls. Therefore, 606 // switch off Checkstyle for this method. 607 608 //CHECKSTYLE:OFF 609 VM._assert(trace.willNotMoveInCurrentCollection(ObjectReference.fromObject(thread.getStack()))); 610 VM._assert(trace.willNotMoveInCurrentCollection(ObjectReference.fromObject(thread))); 611 VM._assert(trace.willNotMoveInCurrentCollection(ObjectReference.fromObject(thread.getStack()))); 612 VM._assert(thread.getJNIEnv() == null || trace.willNotMoveInCurrentCollection(ObjectReference.fromObject(thread.getJNIEnv()))); 613 VM._assert(thread.getJNIEnv() == null || thread.getJNIEnv().refsArray() == null || trace.willNotMoveInCurrentCollection(ObjectReference.fromObject(thread.getJNIEnv().refsArray()))); 614 VM._assert(trace.willNotMoveInCurrentCollection(ObjectReference.fromObject(thread.getContextRegisters()))); 615 VM._assert(trace.willNotMoveInCurrentCollection(ObjectReference.fromObject(thread.getContextRegisters().getGPRs()))); 616 VM._assert(trace.willNotMoveInCurrentCollection(ObjectReference.fromObject(thread.getExceptionRegisters()))); 617 VM._assert(trace.willNotMoveInCurrentCollection(ObjectReference.fromObject(thread.getExceptionRegisters().getGPRs()))); 618 //CHECKSTYLE:ON 619 } 620 621 /** 622 * Print out the basic information associated with the top frame on 623 * the stack. 624 * 625 * @param verbosity The level of verbosity to be used when 626 * performing the scan. 627 */ 628 private void dumpTopFrameInfo(int verbosity) { 629 Log.write(" topFrame = "); Log.writeln(topFrame); 630 Log.write(" ip = "); Log.writeln(ip); 631 Log.write(" fp = "); Log.writeln(fp); 632 Log.write(" registers.ip = "); Log.writeln(thread.getContextRegisters().getIP()); 633 if (verbosity >= 3 && thread.getJNIEnv() != null) 634 thread.getJNIEnv().dumpJniRefsStack(); 635 } 636 637 /** 638 * Print out information associated with a reference. 639 * 640 * @param refaddr The address of the reference in question. 641 * @param verbosity The level of verbosity to be used when 642 * performing the scan. 643 */ 644 private void dumpRef(Address refaddr, int verbosity) { 645 ObjectReference ref = refaddr.loadObjectReference(); 646 VM.sysWrite(refaddr); 647 if (verbosity >= 5) { 648 VM.sysWrite(":"); MemoryManager.dumpRef(ref); 649 } else 650 VM.sysWriteln(); 651 } 652 653 /** 654 * Check that a reference encountered during scanning is valid. If 655 * the reference is invalid, dump stack and die. 656 * 657 * @param refaddr The address of the reference in question. 658 * @param verbosity The level of verbosity to be used when 659 * performing the scan. 660 */ 661 private void checkReference(Address refaddr, int verbosity) { 662 ObjectReference ref = refaddr.loadObjectReference(); 663 if (!MemoryManager.validRef(ref)) { 664 Log.writeln(); 665 Log.writeln("Invalid ref reported while scanning stack"); 666 printMethodHeader(); 667 Log.write(refaddr); Log.write(":"); Log.flush(); MemoryManager.dumpRef(ref); 668 dumpStackFrame(verbosity); 669 Log.writeln(); 670 Log.writeln("Dumping stack starting at frame with bad ref:"); 671 RVMThread.dumpStack(ip, fp); 672 /* dump stack starting at top */ 673 Address top_ip = thread.getContextRegisters().getInnermostInstructionAddress(); 674 Address top_fp = thread.getContextRegisters().getInnermostFramePointer(); 675 RVMThread.dumpStack(top_ip, top_fp); 676 Log.writeln("Failing iterators:"); 677 Offset offset = compiledMethod.getInstructionOffset(ip); 678 iterator = iteratorGroup.selectIterator(compiledMethod); 679 iterator.setupIterator(compiledMethod, offset, fp); 680 int i = 0; 681 for (Address addr = iterator.getNextReferenceAddress(); 682 !addr.isZero(); 683 addr = iterator.getNextReferenceAddress()) { 684 ObjectReference ref2 = addr.loadObjectReference(); 685 Log.write("Iterator "); Log.write(i++); Log.write(": "); Log.write(addr); 686 Log.write(": "); Log.flush(); MemoryManager.dumpRef(ref2); 687 } 688 VM.sysFail("\n\nScanStack: Detected bad GC map; exiting RVM with fatal error"); 689 } 690 } 691 692 /** 693 * Check that a reference encountered during scanning is valid. If 694 * the reference is invalid, dump stack and die. 695 * 696 * @param refaddr The address of the reference in question. 697 */ 698 private static void checkReference(Address refaddr) { 699 ObjectReference ref = refaddr.loadObjectReference(); 700 if (!MemoryManager.validRef(ref)) { 701 Log.writeln(); 702 Log.writeln("Invalid ref reported while scanning stack"); 703 Log.write(refaddr); Log.write(":"); Log.flush(); MemoryManager.dumpRef(ref); 704 Log.writeln(); 705 Log.writeln("Dumping stack:"); 706 RVMThread.dumpStack(); 707 VM.sysFail("\n\nScanStack: Detected bad GC map; exiting RVM with fatal error"); 708 } 709 } 710 /** 711 * Print out the name of a method 712 * 713 * @param m The method to be printed 714 */ 715 private void printMethod(RVMMethod m) { 716 Log.write(m.getMemberRef().getType().getName().toByteArray()); Log.write("."); 717 Log.write(m.getMemberRef().getName().toByteArray()); Log.write(" "); 718 Log.write(m.getMemberRef().getDescriptor().toByteArray()); 719 } 720 721 /** 722 * Print out the method header for the method associated with the 723 * current frame 724 */ 725 private void printMethodHeader() { 726 RVMMethod method = compiledMethod.getMethod(); 727 728 Log.write("\n--- METHOD ("); 729 Log.write(CompiledMethod.compilerTypeToString(compiledMethodType)); 730 Log.write(") "); 731 if (method == null) 732 Log.write("null method"); 733 else 734 printMethod(method); 735 Log.writeln(); 736 Log.write("--- fp = "); 737 Log.write(fp); 738 if (compiledMethod.isCompiled()) { 739 ObjectReference codeBase = ObjectReference.fromObject(compiledMethod.getEntryCodeArray()); 740 Log.write(" code base = "); 741 Log.write(codeBase); 742 Log.write(" code offset = "); 743 Log.writeln(ip.diff(codeBase.toAddress())); 744 Log.write(" line number = "); 745 Log.writeln(compiledMethod.findLineNumberForInstruction(ip.diff(codeBase.toAddress()))); 746 } else { 747 Log.write(" Method is uncompiled - ip = "); 748 Log.writeln(ip); 749 } 750 } 751 752 /** 753 * Dump the contents of a stack frame. Attempts to interpret each 754 * word as an object reference 755 * 756 * @param verbosity The level of verbosity to be used when 757 * performing the scan. 758 */ 759 private void dumpStackFrame(int verbosity) { 760 Address start,end; 761 if (VM.BuildForIA32) { 762 if (prevFp.isZero()) { 763 start = fp.minus(20 * BYTES_IN_ADDRESS); 764 Log.writeln("--- 20 words of stack frame with fp = ", fp); 765 } else { 766 start = prevFp; // start at callee fp 767 } 768 end = fp; // end at fp 769 } else { 770 start = fp; // start at fp 771 end = fp.loadAddress(); // stop at callers fp 772 } 773 774 for (Address loc = start; loc.LT(end); loc = loc.plus(BYTES_IN_ADDRESS)) { 775 Log.write(loc); Log.write(" ("); 776 Log.write(loc.diff(start)); 777 Log.write("): "); 778 ObjectReference value = Selected.Plan.get().loadObjectReference(loc); 779 Log.write(value); 780 Log.write(" "); 781 Log.flush(); 782 if (verbosity >= 4 && MemoryManager.objectInVM(value) && loc.NE(start) && loc.NE(end)) 783 MemoryManager.dumpRef(value); 784 else 785 Log.writeln(); 786 } 787 Log.writeln(); 788 } 789}