* The current frame is expected to be one of the JNI functions called from C,
* The current frame is expected to be one of the JNI functions * called from C,
  private static void deliverException(Throwable exceptionObject, 				       VM_Registers exceptionRegisters) {    if (VM.TraceTimes) VM_Timer.start(VM_Timer.EXCEPTION_HANDLING);    // walk stack and look for a catch block    //    VM_Type exceptionType = VM_Magic.getObjectType(exceptionObject);    int fp = exceptionRegisters.getInnermostFramePointer();    while (VM_Magic.getCallerFramePointer(fp) != STACKFRAME_SENTINAL_FP) {      int compiledMethodId = VM_Magic.getCompiledMethodID(fp);      if (compiledMethodId != INVISIBLE_METHOD_ID) { 	VM_CompiledMethod     compiledMethod     = VM_CompiledMethods.getCompiledMethod(compiledMethodId);	VM_CompilerInfo       compilerInfo       = compiledMethod.getCompilerInfo();	VM_ExceptionDeliverer exceptionDeliverer = compilerInfo.getExceptionDeliverer();	int ip                 = exceptionRegisters.getInnermostInstructionAddress();	int methodStartAddress = VM_Magic.objectAsAddress(compiledMethod.getInstructions());	int catchBlockOffset   = compilerInfo.findCatchBlockForInstruction(ip - methodStartAddress, exceptionType);	if (catchBlockOffset >= 0) { 	  // found an appropriate catch block	  if (VM.TraceTimes) VM_Timer.stop(VM_Timer.EXCEPTION_HANDLING);	  exceptionDeliverer.deliverException(compiledMethod, methodStartAddress + catchBlockOffset, exceptionObject, exceptionRegisters);	  if (VM.VerifyAssertions) VM.assert(NOT_REACHED);	}	exceptionDeliverer.unwindStackFrame(compiledMethod, exceptionRegisters);      } else {	unwindInvisibleStackFrame(exceptionRegisters);      }      fp = exceptionRegisters.getInnermostFramePointer();    }    // no appropriate catch block found    //    if (VM.TraceTimes) VM_Timer.stop(VM_Timer.EXCEPTION_HANDLING);    VM.enableGC();    exceptionObject.printStackTrace();    VM_Thread.terminate();    if (VM.VerifyAssertions) VM.assert(NOT_REACHED);  }  /**   * The current frame is expected to be one of the JNI functions called from C,    * below which is one or more native stack frames   * Skip over all frames below with saved code pointers outside of heap (C frames),    * stopping at the native frame immediately preceding the glue frame which contains   * the method ID of the native method (this is necessary to allow retrieving the    * return address of the glue frame)   * Ton Ngo 7/30/01   */  public static int unwindNativeStackFrame(int currfp) {    int ip, callee_fp;    int fp = VM_Magic.getCallerFramePointer(currfp);    int vmStart = VM_BootRecord.the_boot_record.startAddress;    int vmEnd = VM_BootRecord.the_boot_record.largeStart + VM_BootRecord.the_boot_record.largeSize;    do {      callee_fp = fp;      ip = VM_Magic.getReturnAddress(fp);      fp = VM_Magic.getCallerFramePointer(fp);    } while ( ( ip < vmStart || ip >= vmEnd ) && fp != STACKFRAME_SENTINAL_FP);    return callee_fp;  }  // Unwind stack frame for an <invisible method>.  // See also: VM_ExceptionDeliverer.unwindStackFrame()  //  //!!TODO: Could be a reflective method invoker frame.  //        Does it clobber any non-volatiles?  //        If so, how do we restore them?  // (I don't think our current implementations of reflective method  //  invokers save/restore any nonvolatiles, so we're probably ok. --dave 6/29/01  private static void unwindInvisibleStackFrame(VM_Registers registers) {    registers.unwindStackFrame();  }