VM.sysWrite(" at offset ", offset); VM.sysWrite(".\n");
VM.sysWriteln(" at offset ", offset);
  private static void scanThreadInternal (AddressQueue rootLocations, AddressPairQueue codeLocations,					 VM_Thread t, VM_Address top_frame) {        VM_CollectorThread collector = VM_Magic.threadAsCollectorThread(VM_Thread.getCurrentThread());    VM_Address             ip, fp, prevFp;    VM_CompiledMethod      compiledMethod;    // Don't forget ip in hardwareExceptionRegisters, if it is in use.    //    if (codeLocations != null && t.hardwareExceptionRegisters.inuse) {      ip = t.hardwareExceptionRegisters.ip;      compiledMethod = VM_CompiledMethods.findMethodForInstruction(ip);      if (VM.VerifyAssertions) VM._assert(compiledMethod != null);      compiledMethod.setObsolete( false );      VM_Address code = VM_Magic.objectAsAddress( compiledMethod.getInstructions());      VM_Address ipLoc = t.hardwareExceptionRegisters.getIPLocation();      codeLocationsPush(codeLocations, code, ipLoc, 1, t);    }    // get gc thread local iterator group from our VM_CollectorThread object    VM_GCMapIteratorGroup iteratorGroup = collector.iteratorGroup;    iteratorGroup.newStackWalk(t);        if (TRACE_STACKS) VM.sysWriteln("Scanning thread ", t.getIndex());    if (top_frame.isZero()) {      prevFp = VM_Address.zero();      // start scan using fp & ip in threads saved context registers      ip = t.contextRegisters.getInnermostInstructionAddress();      fp = t.contextRegisters.getInnermostFramePointer();    }    else {      prevFp = top_frame;      // start scan at caller of passed in fp      ip = VM_Magic.getReturnAddress(top_frame);      fp = VM_Magic.getCallerFramePointer(top_frame);    }    if (TRACE_STACKS) {      VM.sysWrite("  top_frame = "); VM.sysWrite(top_frame); VM.sysWrite("\n");      VM.sysWrite("         ip = "); VM.sysWrite(ip); VM.sysWrite("\n");      VM.sysWrite("         fp = "); VM.sysWrite(fp); VM.sysWrite("\n");      VM.sysWrite("  registers.ip = "); VM.sysWrite(t.contextRegisters.ip); VM.sysWrite("\n");    }        if (DUMP_STACK_REFS > 0 && t.jniEnv != null) t.jniEnv.dumpJniRefsStack();    // It is possible to have a stack with only Native C frames, for a thread    // that started in C, "attached" to the VM, made JNIFunction calls, and    // has now returned back to C. In this case, scanStack should be called    // with a "topJavaFrame" = 0. There may be references in the threads    // JNIrefs side stack that need to be processed, below after the loop.    if ( fp.NE(VM_Address.fromInt(STACKFRAME_SENTINAL_FP)) ) {      // At start of loop:      //   fp -> frame for method invocation being processed      //   ip -> instruction pointer in the method (normally a call site)            while (VM_Magic.getCallerFramePointer(fp).NE(VM_Address.fromInt(STACKFRAME_SENTINAL_FP))) {		int compiledMethodId = VM_Magic.getCompiledMethodID(fp);		// reflection and jni generate "invisible" transition frames with	// method_id == 0.  reflections frames are skipped here. For PowerPC	// JNI C to java transitions frames exist, but should be skipped at the	// end of this loop during incrementing tothe "next" frame.	//	if (compiledMethodId == VM_Constants.INVISIBLE_METHOD_ID) {	  	  if (TRACE_STACKS) VM.sysWrite("\n--- METHOD --- <invisible method>\n");	  	  // skip "invisible" frame	  prevFp = fp;	  ip = VM_Magic.getReturnAddress(fp);	  fp = VM_Magic.getCallerFramePointer(fp);	  continue;	}		// following is for normal Java (and JNI Java to C transition) frames	compiledMethod = VM_CompiledMethods.getCompiledMethod(compiledMethodId);	compiledMethod.setObsolete( false );	int compiledMethodType = compiledMethod.getCompilerType();	if (compiledMethodType == VM_CompiledMethod.TRAP) continue;	VM_Method method = compiledMethod.getMethod();		// initialize MapIterator for this frame	int offset = ip.diff(VM_Magic.objectAsAddress(compiledMethod.getInstructions())).toInt();	VM_GCMapIterator iterator = iteratorGroup.selectIterator(compiledMethod);	iterator.setupIterator(compiledMethod, offset, fp);		if (TRACE_STACKS) {	  VM_Scheduler.outputMutex.lock();	  VM.sysWrite("\n--- METHOD --- ");	  VM.sysWrite(method);	  VM.sysWrite(" at offset ", offset);	  VM.sysWrite(".\n");	  VM_Scheduler.outputMutex.unlock();	}	if (DUMP_STACK_FRAMES) dumpStackFrame( fp, prevFp );		if (DUMP_STACK_REFS > 0) 	  VM.sysWrite("--- Refs Reported By GCMap Iterator ---\n");		if (false) {	  VM.sysWrite("--- FRAME DUMP of METHOD ");	  VM.sysWrite(method);	  VM.sysWriteln(" at offset ", offset);	  VM.sysWrite(" fp = "); VM.sysWrite(fp);	  VM.sysWrite(" ip = "); VM.sysWrite(ip); VM.sysWrite("\n");	  dumpStackFrame( fp, prevFp );	}		// scan the map for this frame and process each reference	//	for (VM_Address refaddr = iterator.getNextReferenceAddress();  !refaddr.isZero();	     refaddr = iterator.getNextReferenceAddress()) {	  	  if (VM.VerifyAssertions && VALIDATE_STACK_REFS) {	    VM_Address ref = VM_Address.fromInt(VM_Magic.getMemoryWord(refaddr));	    if (!VM_Interface.validRef(ref)) {	      VM.sysWrite("\nInvalid ref reported while scanning stack\n");	      VM.sysWrite("--- METHOD --- ");	      VM.sysWrite(method);	      VM.sysWriteln(" at offset ", offset);	      VM.sysWrite(" fp = ", fp);	      VM.sysWriteln(" ip = ", ip);	      // dump out bad ref	      VM.sysWrite(refaddr); VM.sysWrite(":"); VM_Interface.dumpRef(ref);	      // dump out contents of frame	      dumpStackFrame( fp, prevFp );	      // dump stack starting at current frame	      VM.sysWrite("\nDumping stack starting at frame with bad ref:\n");	      VM_Scheduler.dumpStack( ip, fp );	      // start stact starting at top	      VM_Address top_ip = t.contextRegisters.getInnermostInstructionAddress();	      VM_Address top_fp = t.contextRegisters.getInnermostFramePointer();	      VM_Scheduler.dumpStack( top_ip, top_fp );	      VM.sysFail("\n\nVM_ScanStack: Detected bad GC map; exiting RVM with fatal error");	    }	  }	  if (DUMP_STACK_REFS >= 1) {	    VM_Address ref = VM_Magic.getMemoryAddress(refaddr);	    VM.sysWrite(refaddr); 	    if (DUMP_STACK_REFS >= 2) {		VM.sysWrite(":"); VM_Interface.dumpRef(ref);	    }	    else		VM.sysWriteln();	  }	  	  rootLocations.push(refaddr);      }      if (codeLocations != null) {	// process the code object for the method, and if it is moved, relocate	// the saved ip and any internal code pointers (JSR subroutine return	// addresses. Note, the instructions field of the VM_Method object is	// NOT updated at this time, so that other invocations of the same	// method can use the original address to compute the relocation delta.	//	VM_Address code = VM_Magic.objectAsAddress( compiledMethod.getInstructions() );	if (codeLocations != null) {	  	  code = VM_Magic.objectAsAddress( compiledMethod.getInstructions() );	  if (prevFp.isZero()) {	    // top-most stack frame, ip saved in threads context regs	      if (DUMP_STACK_REFS >= 2) {		VM.sysWriteln(" t.contextRegisters.ip    = ", t.contextRegisters.ip);		VM.sysWriteln("*t.contextRegisters.iploc = ", VM_Magic.getMemoryAddress(t.contextRegisters.getIPLocation()));	      }	      if (compiledMethodType != VM_CompiledMethod.JNI)		codeLocationsPush(codeLocations, code, t.contextRegisters.getIPLocation(), 2, t);	      else		VM.sysWriteln("XXXX SKIPPING return address for JNI code XXXX");	  }	  else {              VM_Address returnAddressLoc = VM_Magic.getReturnAddressLocation(prevFp);	      VM_Address returnAddress = VM_Magic.getMemoryAddress(returnAddressLoc);	      if (!Util.addrInBootImage(returnAddress))		  codeLocationsPush(codeLocations, code, returnAddressLoc, 3, t);	  }	  // scan for internal code pointers in the stack frame and relocate	  iterator.reset();	  for (VM_Address retaddrLoc = iterator.getNextReturnAddressAddress();  !retaddrLoc.isZero();	       retaddrLoc = iterator.getNextReturnAddressAddress()) {	    codeLocationsPush(codeLocations, code, retaddrLoc, 4, t);	  }	}      }             iterator.cleanupPointers();            // if at a JNIFunction method, it is preceeded by native frames that must be skipped      //      if (compiledMethod.getMethod().getDeclaringClass().isBridgeFromNative()) {	// skip native frames, stopping at last native frame PRECEEDING the	// Java To C transition frame	fp = VM_Runtime.unwindNativeStackFrame(fp);		if ( TRACE_STACKS ) VM.sysWrite("scanStack skipping native C frames\n");      }                   // set fp & ip for next frame      prevFp = fp;      ip = VM_Magic.getReturnAddress(fp);      fp = VM_Magic.getCallerFramePointer(fp);            } // end of while != sentinel          } // end of if (fp != STACKFRAME_SENTINAL_FP)        // if we are scanning the stack of a thread that entered the VM    // via a createJVM or attachJVM 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)    //    //-#if RVM_FOR_AIX    VM_GCMapIterator iterator = iteratorGroup.getJniIterator();    VM_Address refaddr =  iterator.getNextReferenceAddress();    while( !refaddr.isZero() ) {      rootLocations.push(refaddr);      refaddr =  iterator.getNextReferenceAddress();    }    //-#else    // exclude PPC FOR LINUX    //-#endif        if (TRACE_STACKS) VM.sysWrite("--- End Of Stack Scan ---\n");      } // scanStack