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