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 }