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