VM_ProcessorLocalState.emitMoveRegToField(asm, VM_Entrypoints.framePointerOffset, FP);
  static void generateGlueCodeForJNIMethod(VM_Assembler asm, VM_Method method, int methodID) {    int bootRecordAddress = VM_Magic.objectAsAddress(VM_BootRecord.the_boot_record);    // set 2nd word of header = return address already pushed by CALL    asm.emitPUSH_Reg(FP);              // start new frame:  set FP to point to the new frame    asm.emitMOV_Reg_Reg (FP, SP);     // set first word of header: method ID    asm.emitPUSH_Imm (methodID);     asm.emitSUB_Reg_Imm (SP, WORDSIZE);  // leave room for saved -> preceeding java frame, set later    // save registers that will be used in RVM, to be restored on return to C    asm.emitPUSH_Reg(JTOC);     asm.emitPUSH_Reg(EBX);             asm.emitPUSH_Reg(S0);             VM_ProcessorLocalState.emitPushProcessor(asm);         // copy the arguments in reverse order    VM_Type[] types = method.getParameterTypes();   // does NOT include implicit this or class ptr    int numArguments = types.length;                // number of arguments for this method    int argOffset = 2;           // add 2 to get to arg area in caller frame    for (int i=0; i<numArguments; i++) {      if (types[i].isLongType() || types[i].isDoubleType()) {        // handle 2-words case:        asm.emitMOV_Reg_RegDisp (EBX, FP, ((argOffset+1)*WORDSIZE));          asm.emitPUSH_Reg(EBX);        asm.emitMOV_Reg_RegDisp (EBX, FP, (argOffset*WORDSIZE));          asm.emitPUSH_Reg(EBX);        argOffset+=2;      } else {        // Handle 1-word case:        // add 2 to get to arg area in caller frame        asm.emitMOV_Reg_RegDisp (EBX, FP, (argOffset*WORDSIZE));          asm.emitPUSH_Reg(EBX);        argOffset++;      }    }    // START of code sequence to atomically change processor status from IN_NATIVE    // to IN_JAVA, looping in a call to sysVirtualProcessorYield if BLOCKED_IN_NATIVE    int retryLabel = asm.getMachineCodeIndex();     // backward branch label    // Restore JTOC through the JNIEnv passed back from the C code as the first parameter:    // an extra entry at the end of the JNIFunctions array contains the RVM JTOC    //    // NOTE - we need the JTOC here only to get the sysYield.. entry point out of the    // bootrecord. we could alternatively also put the bootrecord address at the end    // of JNIFunctions or put it there INSTEAD of the JTOC    asm.emitMOV_Reg_RegDisp (EBX, FP, (2*WORDSIZE));   // pick up arg 0 (from callers frame)    asm.emitMOV_Reg_RegDisp (JTOC, EBX, 0);                         // JTOC<-addr of JNIFunctions[0]    asm.emitMOV_Reg_RegDisp (JTOC, JTOC, JNIFUNCTIONS_JTOC_OFFSET); // JTOC<-JNIFunctions[saved JTOC]    // address of current processors status word is stored at jniEnv (first arg) + 4;    asm.emitMOV_Reg_RegDisp (S0, EBX, WORDSIZE);     // S0 <- addr of status word    asm.emitMOV_Reg_RegInd(T0,S0);                         // T0<-contents of statusword     asm.emitCMP_Reg_Imm (T0, VM_Processor.IN_NATIVE);      // jmp if still IN_NATIVE    VM_ForwardReference fr = asm.forwardJcc(asm.EQ);       // if so, skip 3 instructions    // blocked in native, do pthread yield    asm.emitMOV_Reg_RegDisp(T0, JTOC, VM_Entrypoints.the_boot_recordOffset);  // T0<-bootrecord addr    asm.emitCALL_RegDisp(T0, VM_Entrypoints.sysVirtualProcessorYieldIPOffset);    asm.emitJMP_Imm (retryLabel);                          // retry from beginning    fr.resolve(asm);      // branch here if IN_NATIVE, attempt to go to IN_JAVA    // T0 (EAX) contains "old value" (required for CMPXCNG instruction)    // S0 contains address of status word to be swapped    asm.emitMOV_Reg_Imm (T1, VM_Processor.IN_JAVA);  // T1<-new value (IN_JAVA)    asm.emitCMPXCHG_RegInd_Reg(S0,T1);               // atomic compare-and-exchange    asm.emitJCC_Cond_Imm(asm.NE,retryLabel);    // END of code sequence to change state from IN_NATIVE to IN_JAVA    // status is now IN_JAVA. GC can not occur while we execute on a processor    // in this state, so it is safe to access fields of objects    // JTOC reg has been restored to RVM JTOC    // done saving, bump SP to reserve room for the local variables    // SP should now be at the point normally marked as emptyStackOffset    int numLocalVariables = method.getLocalWords() - method.getParameterWords();    asm.emitSUB_Reg_Imm (SP, (numLocalVariables << LG_WORDSIZE));       // Compute the byte offset for this thread (offset into the VM_Scheduler.threads array)    asm.emitMOV_Reg_RegDisp (S0, JTOC, VM_Entrypoints.JNIFunctionPointersOffset);   // S0 <- base addr    asm.emitSUB_Reg_Reg (EBX, S0);                     // ebx <- offset    asm.emitSHR_Reg_Imm (EBX, 1);                      // byte offset:  divide by 2 (=> off in threads array)    // then get the thread and its real JNIEnv    asm.emitMOV_Reg_RegDisp (S0, JTOC, VM_Entrypoints.threadsOffset);   // S0 <- VM_Thread array    asm.emitMOV_Reg_RegIdx  (S0, S0, EBX, asm.BYTE, 0);                 // S0 <- VM_Thread object    asm.emitMOV_Reg_RegDisp (EBX, S0, VM_Entrypoints.jniEnvOffset);     // ebx <- JNIenv    // now EBX -> jniEnv for thread    // Retrieve -> preceeding "top" java FP from jniEnv and save in current     // frame of JNIFunction    asm.emitMOV_Reg_RegDisp (ESI, EBX, VM_Entrypoints.JNITopJavaFPOffset);      // asm.emitMOV_Reg_RegDisp (PR, EBX, VM_Entrypoints.JNITopJavaFPOffset);          // get offset from current FP (PR <- PR - FP)    asm.emitSUB_Reg_Reg (ESI, FP);        asm.emitMOV_RegDisp_Reg (FP, SAVED_JAVA_FP_OFFSET, ESI);                // save in hdr of current frame     // Restore the VM_Processor value saved on the Java to C transition    VM_ProcessorLocalState.emitSetProcessor(asm, EBX,                                         VM_Entrypoints.JNIEnvSavedPROffset);        // Test if calling Java JNIFunction on a RVM processor or     // a Native processor.    // at this point: JTOC and PR have been restored &     // processor status = IN_JAVA,    // arguments for the call have been setup, space on the stack for locals    // has been acquired.    // load mode of current processor for testing (RVM or NATIVE)    VM_ProcessorLocalState.emitMoveFieldToReg(asm, T0,                                              VM_Entrypoints.processorModeOffset);    asm.emitCMP_Reg_Imm (T0, VM_Processor.RVM);           // test for RVM    VM_ForwardReference fr1 = asm.forwardJcc(asm.EQ);     // Br if yes    // If here, on a native processor, it is necessary to transfer back to a    // RVM processor before executing the Java JNI Function.    // !!! what about saving regs, especially FPRs ??? (CHECK)    // branch to becomeRVMThread to make the transfer.    // If GC occurs while we are on the transfer queue of the RVM processor,    // what will the MapIterator do, will we appear to be in the prolog of the     // Java JNI Function? Will there be any refs to report? any saved regs to report?    asm.emitCALL_RegDisp(JTOC, VM_Entrypoints.becomeRVMThreadOffset);    // execution here is now on the RVM processor, and on a different    // os pThread. PR now points to the new RVM processor we have    // been transferred to.  JTOC was set when we were re-dispatched.    // XXX Restoring regs? especially FPRs ??? (CHECK)    fr1.resolve(asm);  // branch to here if returning on a RVM processor    // finally proceed with the normal Java compiled code    // skip the thread switch test for now, see VM_Compiler.genThreadSwitchTest(true)    asm.emitNOP(); // end of prologue marker  }