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 }