org.jikesrvm.mm.mmtk
Class ScanThread

java.lang.Object
  extended by org.jikesrvm.mm.mmtk.ScanThread
All Implemented Interfaces:
Constants, HeapLayoutConstants, ThinLockConstants, TIBLayoutConstants, SizeConstants

public final class ScanThread
extends Object
implements Constants

Class that supports scanning thread stacks for references during collections. References are located using GCMapIterators and are inserted into a set of root locations. Optionally, a set of interior pointer locations associated with the object is created.

Threads, stacks, jni environments, and register objects have a complex interaction in terms of scanning. The operation of scanning the stack reveals not only roots inside the stack but also the state of the register objects's gprs and the JNI refs array. They are all associated via the thread object, making it natural for scanThread to be considered a single operation with the method directly accessing these objects via the thread object's fields.

One pitfall occurs when scanning the thread object (plus dependents) when not all of the objects have been copied. Then it may be that the innards of the register object has not been copied while the stack object has. The result is that an inconsistent set of slots is reported. In this case, the copied register object may not be correct if the copy occurs after the root locations are discovered but before those locations are processed. In essence, all of these objects form one logical unit but are physically separated so that sometimes only part of it has been copied causing the scan to be incorrect.

The caller of the stack scanning routine must ensure that all of these components's descendants are consistent (all copied) when this method is called.

Code locations: Identifying pointers into code objects is essential if code objects are allowed to move (and if the code objects were not otherwise kept alive, it would be necessary to ensure the liveness of the code objects). A code pointer is the only case in which we have interior pointers (pointers into the inside of objects). For such pointers, two things must occur: first the pointed to object must be kept alive, and second, if the pointed to object is moved by a copying collector, the pointer into the object must be adjusted so it now points into the newly copied object.


Field Summary
private  CompiledMethod compiledMethod
           
private  int compiledMethodType
           
private static int DEFAULT_VERBOSITY
           
private  boolean failed
           
private static int FAILURE_VERBOSITY
           
private  Address fp
           
private  Address initialIPLoc
           
private  Address ip
           
private  GCMapIterator iterator
           
private  GCMapIteratorGroup iteratorGroup
           
private  Address prevFp
           
private  boolean processCodeLocations
           
private  RVMThread thread
           
private  Address topFrame
           
private  TraceLocal trace
           
(package private) static boolean VALIDATE_REFS
          quietly validates each ref reported by map iterators
 
Fields inherited from interface org.jikesrvm.Constants
NOT_REACHED, REFLECTION_FPRS_BITS, REFLECTION_FPRS_MASK, REFLECTION_GPRS_BITS, REFLECTION_GPRS_MASK
 
Fields inherited from interface org.jikesrvm.objectmodel.ThinLockConstants
TL_DEDICATED_U16_OFFSET, TL_DEDICATED_U16_SHIFT, TL_LOCK_COUNT_MASK, TL_LOCK_COUNT_SHIFT, TL_LOCK_COUNT_UNIT, TL_LOCK_ID_MASK, TL_LOCK_ID_SHIFT, TL_NUM_BITS_RC, TL_NUM_BITS_STAT, TL_NUM_BITS_TID, TL_STAT_BIASABLE, TL_STAT_FAT, TL_STAT_MASK, TL_STAT_SHIFT, TL_STAT_THIN, TL_THREAD_ID_MASK, TL_THREAD_ID_SHIFT, TL_UNLOCK_MASK
 
Fields inherited from interface org.jikesrvm.SizeConstants
BITS_IN_ADDRESS, BITS_IN_BOOLEAN, BITS_IN_BYTE, BITS_IN_CHAR, BITS_IN_DOUBLE, BITS_IN_EXTENT, BITS_IN_FLOAT, BITS_IN_INT, BITS_IN_LONG, BITS_IN_OFFSET, BITS_IN_PAGE, BITS_IN_SHORT, BITS_IN_WORD, BYTES_IN_ADDRESS, BYTES_IN_BOOLEAN, BYTES_IN_BYTE, BYTES_IN_CHAR, BYTES_IN_DOUBLE, BYTES_IN_EXTENT, BYTES_IN_FLOAT, BYTES_IN_INT, BYTES_IN_LONG, BYTES_IN_OFFSET, BYTES_IN_PAGE, BYTES_IN_SHORT, BYTES_IN_WORD, LOG_BITS_IN_ADDRESS, LOG_BITS_IN_BOOLEAN, LOG_BITS_IN_BYTE, LOG_BITS_IN_CHAR, LOG_BITS_IN_DOUBLE, LOG_BITS_IN_EXTENT, LOG_BITS_IN_FLOAT, LOG_BITS_IN_INT, LOG_BITS_IN_LONG, LOG_BITS_IN_OFFSET, LOG_BITS_IN_PAGE, LOG_BITS_IN_SHORT, LOG_BITS_IN_WORD, LOG_BYTES_IN_ADDRESS, LOG_BYTES_IN_BOOLEAN, LOG_BYTES_IN_BYTE, LOG_BYTES_IN_CHAR, LOG_BYTES_IN_DOUBLE, LOG_BYTES_IN_EXTENT, LOG_BYTES_IN_FLOAT, LOG_BYTES_IN_INT, LOG_BYTES_IN_LONG, LOG_BYTES_IN_OFFSET, LOG_BYTES_IN_PAGE, LOG_BYTES_IN_SHORT, LOG_BYTES_IN_WORD
 
Fields inherited from interface org.jikesrvm.objectmodel.TIBLayoutConstants
IMT_METHOD_SLOTS, NEEDS_DYNAMIC_LINK, TIB_ARRAY_ELEMENT_TIB_INDEX, TIB_DOES_IMPLEMENT_INDEX, TIB_FIRST_SPECIALIZED_METHOD_INDEX, TIB_FIRST_VIRTUAL_METHOD_INDEX, TIB_INTERFACE_DISPATCH_TABLE_INDEX, TIB_SUPERCLASS_IDS_INDEX, TIB_TYPE_INDEX
 
Fields inherited from interface org.jikesrvm.HeapLayoutConstants
BAD_MAP_COMPRESSION, BOOT_IMAGE_CODE_END, BOOT_IMAGE_CODE_SIZE, BOOT_IMAGE_CODE_START, BOOT_IMAGE_DATA_END, BOOT_IMAGE_DATA_SIZE, BOOT_IMAGE_DATA_START, BOOT_IMAGE_END, BOOT_IMAGE_RMAP_END, BOOT_IMAGE_RMAP_START, MAX_BOOT_IMAGE_RMAP_SIZE, MAXIMUM_MAPPABLE
 
Constructor Summary
ScanThread()
           
 
Method Summary
private  void assertImmovableInCurrentCollection()
          Assert that the stack is immovable.
private  void checkJNIBase()
          AIX-specific code.
private static void checkReference(Address refaddr)
          Check that a reference encountered during scanning is valid.
private  void checkReference(Address refaddr, int verbosity)
          Check that a reference encountered during scanning is valid.
private  void dumpRef(Address refaddr, int verbosity)
          Print out information associated with a reference.
private  void dumpStackFrame(int verbosity)
          Dump the contents of a stack frame.
private  void dumpTopFrameInfo(int verbosity)
          Print out the basic information associated with the top frame on the stack.
private  void getHWExceptionRegisters()
          When an exception occurs, registers are saved temporarily.
private  void printMethod(RVMMethod m)
          Print out the name of a method
private  void printMethodHeader()
          Print out the method header for the method associated with the current frame
private  void processCodeLocation(ObjectReference code, Address ipLoc)
          Push a code pointer location onto the code locations deque, optionally performing a sanity check first.
private  void processFrameForCode(int verbosity)
          Identify all pointers into code pointers associated with a frame.
private  void pushFrameIP(ObjectReference code, int verbosity)
          Push the instruction pointer associated with this frame onto the code locations deque.
private static void reportDelayedRootEdge(TraceLocal trace, Address addr)
          Wrapper for TraceLocal.reportDelayedRootEdge(Address) that allows sanity checking of the address.
private  Address scanFrame(int verbosity)
          Scan the current stack frame.
private  void scanFrameForCode(ObjectReference code)
          Scan this frame for internal code pointers.
private  void scanFrameForObjects(int verbosity)
          Identify all the object pointers stored as local variables associated with (though not necessarily strictly within!)
static void scanThread(RVMThread thread, TraceLocal trace, boolean processCodeLocations)
          Scan a thread, placing the addresses of pointers into supplied buffers.
private static void scanThread(RVMThread thread, TraceLocal trace, boolean processCodeLocations, Address gprs, Address topFrame)
          A more general interface to thread scanning, which permits the scanning of stack segments which are dislocated from the thread structure.
private  void scanThreadInternal(Address gprs, int verbosity)
          The main stack scanning loop.
private  boolean setUpFrame(int verbosity)
          Set up to scan the current stack frame.
private  void startScan(TraceLocal trace, boolean processCodeLocations, RVMThread thread, Address gprs, Address ip, Address fp, Address initialIPLoc, Address topFrame)
          Initializes a ScanThread instance, and then scans a stack associated with a thread, and places references in deques (one for object pointers, one for interior code pointers).
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

VALIDATE_REFS

static final boolean VALIDATE_REFS
quietly validates each ref reported by map iterators

See Also:
Constant Field Values

DEFAULT_VERBOSITY

private static final int DEFAULT_VERBOSITY
See Also:
Constant Field Values

FAILURE_VERBOSITY

private static final int FAILURE_VERBOSITY
See Also:
Constant Field Values

iteratorGroup

private final GCMapIteratorGroup iteratorGroup

iterator

private GCMapIterator iterator

trace

private TraceLocal trace

processCodeLocations

private boolean processCodeLocations

thread

private RVMThread thread

ip

private Address ip

fp

private Address fp

prevFp

private Address prevFp

initialIPLoc

private Address initialIPLoc

topFrame

private Address topFrame

compiledMethod

private CompiledMethod compiledMethod

compiledMethodType

private int compiledMethodType

failed

private boolean failed
Constructor Detail

ScanThread

public ScanThread()
Method Detail

scanThread

public static void scanThread(RVMThread thread,
                              TraceLocal trace,
                              boolean processCodeLocations)
Scan a thread, placing the addresses of pointers into supplied buffers.

Parameters:
thread - The thread to be scanned
trace - The trace instance to use for reporting references.
processCodeLocations - Should code locations be processed?

reportDelayedRootEdge

private static void reportDelayedRootEdge(TraceLocal trace,
                                          Address addr)
Wrapper for TraceLocal.reportDelayedRootEdge(Address) that allows sanity checking of the address.


scanThread

private static void scanThread(RVMThread thread,
                               TraceLocal trace,
                               boolean processCodeLocations,
                               Address gprs,
                               Address topFrame)
A more general interface to thread scanning, which permits the scanning of stack segments which are dislocated from the thread structure.

Parameters:
thread - The thread to be scanned
trace - The trace instance to use for reporting references.
processCodeLocations - Should code locations be processed?
gprs - The general purpose registers associated with the stack being scanned (normally extracted from the thread).
topFrame - The top frame of the stack being scanned, or zero if this is to be inferred from the thread (normally the case).

startScan

private void startScan(TraceLocal trace,
                       boolean processCodeLocations,
                       RVMThread thread,
                       Address gprs,
                       Address ip,
                       Address fp,
                       Address initialIPLoc,
                       Address topFrame)
Initializes a ScanThread instance, and then scans a stack associated with a thread, and places references in deques (one for object pointers, one for interior code pointers). If the thread scan fails, the thread is rescanned verbosely and a failure occurs.

The various state associated with stack scanning is captured by instance variables of this type, which are initialized here.

Parameters:
trace - The trace instance to use for reporting locations.
thread - Thread for the thread whose stack is being scanned
gprs - The general purpose registers associated with the stack being scanned (normally extracted from the thread).
ip - The instruction pointer for the top frame of the stack we're about to scan.
fp - The frame pointer for the top frame of the stack we're about to scan.

scanThreadInternal

private void scanThreadInternal(Address gprs,
                                int verbosity)
The main stack scanning loop.

Walk the stack one frame at a time, top (lo) to bottom (hi),

Parameters:
gprs - The general purpose registers associated with the stack being scanned (normally extracted from the thread).
verbosity - The level of verbosity to be used when performing the scan.

getHWExceptionRegisters

private void getHWExceptionRegisters()
When an exception occurs, registers are saved temporarily. If the stack being scanned is in this state, we need to scan those registers for code pointers. If the codeLocations deque is null, then scanning for code pointers is not required, so we don't need to do anything. (SB: Why only code pointers?). Dave G: The contents of the GPRs of the exceptionRegisters are handled during normal stack scanning (@see org.jikesrvm.runtime.compilers.common.HardwareTrapCompiledMethod. It looks to me like the main goal of this method is to ensure that the method in which the trap happened isn't treated as dead code and collected (if it's been marked as obsolete, we are setting its activeOnStackFlag below).


processCodeLocation

private void processCodeLocation(ObjectReference code,
                                 Address ipLoc)
Push a code pointer location onto the code locations deque, optionally performing a sanity check first.

Parameters:
code - The code object into which this interior pointer points
ipLoc - The location of the pointer into this code object

scanFrame

private Address scanFrame(int verbosity)
Scan the current stack frame.

First the various iterators are set up, then the frame is scanned for regular pointers, before scanning for code pointers. The iterators are then cleaned up, and native frames skipped if necessary.

Parameters:
verbosity - The level of verbosity to be used when performing the scan.

setUpFrame

private boolean setUpFrame(int verbosity)
Set up to scan the current stack frame. This means examining the frame to discover the method being invoked and then retrieving the associated metadata (stack maps etc). Certain frames should not be scanned---these are identified and skipped.

Parameters:
verbosity - The level of verbosity to be used when performing the scan.
Returns:
True if the frame should be scanned, false if it should be skipped.

scanFrameForObjects

private void scanFrameForObjects(int verbosity)
Identify all the object pointers stored as local variables associated with (though not necessarily strictly within!) the current frame. Loop through the GC map iterator, getting the address of each object pointer, adding them to the root locations deque.

NOTE: Because of the callee save policy of the optimizing compiler, references associated with a given frame may be in callee stack frames (lower memory), outside the current frame. So the iterator may return locations that are outside the frame being scanned.

Parameters:
verbosity - The level of verbosity to be used when performing the scan.

processFrameForCode

private void processFrameForCode(int verbosity)
Identify all pointers into code pointers associated with a frame. There are two cases to be considered: a) the instruction pointer associated with each frame (stored in the thread's metadata for the top frame and as a return address for all subsequent frames), and b) local variables on the stack which happen to be pointers to code.

FIXME: SB: Why is it that JNI frames are skipped when considering top of stack frames, while boot image frames are skipped when considering other frames. Shouldn't they both be considered in both cases?

Parameters:
verbosity - The level of verbosity to be used when performing the scan.

pushFrameIP

private void pushFrameIP(ObjectReference code,
                         int verbosity)
Push the instruction pointer associated with this frame onto the code locations deque.

A stack frame represents an execution context, and thus has an instruction pointer associated with it. In the case of the top frame, the instruction pointer is captured by the IP register, which is preserved in the thread data structure at thread switch time. In the case of all non-top frames, the next instruction pointer is stored as the return address for the previous frame.

The address of the code pointer is pushed onto the code locations deque along with the address of the code object into which it points (both are required since the former is an internal pointer).

The code pointers are updated later (after stack scanning) when the code locations deque is processed. The pointer from RVMMethod to the code object is not updated until after stack scanning, so the pointer to the (uncopied) code object is available throughout the stack scanning process, which enables interior pointer offsets to be correctly computed.

Parameters:
verbosity - The level of verbosity to be used when performing the scan.

scanFrameForCode

private void scanFrameForCode(ObjectReference code)
Scan this frame for internal code pointers. The GC map iterator is used to identify any local variables (stored on the stack) which happen to be pointers into code.

Parameters:
code - The code object associated with this frame.

checkJNIBase

private void checkJNIBase()
AIX-specific code.

If we are scanning the stack of a thread that entered the VM via a createVM or attachVM then the "bottom" of the stack had native C frames instead of the usual java frames. The JNIEnv for the thread may still contain jniRefs that have been returned to the native C code, but have not been reported for GC. calling getNextReferenceAddress without first calling setup... will report the remaining jniRefs in the current "frame" of the jniRefs stack. (this should be the bottom frame)

FIXME: SB: Why is this AIX specific? Why depend on the preprocessor?


assertImmovableInCurrentCollection

private void assertImmovableInCurrentCollection()
Assert that the stack is immovable.

Currently we do not allow stacks to be moved within the heap. If a stack contains native stack frames, then it is impossible for us to safely move it. Prior to the implementation of JNI, Jikes RVM did allow the GC system to move thread stacks, and called a special fixup routine, thread.fixupMovedStack to adjust all of the special interior pointers (SP, FP). If we implement split C & Java stacks then we could allow the Java stacks to be moved, but we can't move the native stack.


dumpTopFrameInfo

private void dumpTopFrameInfo(int verbosity)
Print out the basic information associated with the top frame on the stack.

Parameters:
verbosity - The level of verbosity to be used when performing the scan.

dumpRef

private void dumpRef(Address refaddr,
                     int verbosity)
Print out information associated with a reference.

Parameters:
refaddr - The address of the reference in question.
verbosity - The level of verbosity to be used when performing the scan.

checkReference

private void checkReference(Address refaddr,
                            int verbosity)
Check that a reference encountered during scanning is valid. If the reference is invalid, dump stack and die.

Parameters:
refaddr - The address of the reference in question.
verbosity - The level of verbosity to be used when performing the scan.

checkReference

private static void checkReference(Address refaddr)
Check that a reference encountered during scanning is valid. If the reference is invalid, dump stack and die.

Parameters:
refaddr - The address of the reference in question.

printMethod

private void printMethod(RVMMethod m)
Print out the name of a method

Parameters:
m - The method to be printed

printMethodHeader

private void printMethodHeader()
Print out the method header for the method associated with the current frame


dumpStackFrame

private void dumpStackFrame(int verbosity)
Dump the contents of a stack frame. Attempts to interpret each word as an object reference

Parameters:
verbosity - The level of verbosity to be used when performing the scan.