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    }