asm.emitSUB_RegDisp_Imm(EBP, Offset.fromIntSignExtend(2*WORDSIZE), VM_Entrypoints.JNIExternalFunctionsField.getOffsetAsInt());
asm.emitSUB_RegDisp_Imm(EBP, Offset.fromIntSignExtend(2*WORDSIZE), VM_Entrypoints.JNIExternalFunctionsField.getOffset().toInt());
  public static void generateGlueCodeForJNIMethod(VM_Assembler asm, VM_NormalMethod method, int methodID) {    // set 2nd word of header = return address already pushed by CALL    // NOTE: C calling convention is that EBP contains the caller's framepointer.    //       Therefore our C to Java transition frames must follow this protocol,    //       not the RVM protocol in which the caller's framepointer is in     //       pr.framePointer and EBP is a nonvolatile register.    asm.emitPUSH_Reg(EBP);              // start new frame:  set FP to point to the new frame    asm.emitMOV_Reg_Reg (EBP, SP);     // set first word of header: method ID    asm.emitPUSH_Imm (methodID);    // buy space for the rest of the header (values stored later)    asm.emitSUB_Reg_Imm (SP, STACKFRAME_HEADER_SIZE - 2 * WORDSIZE);    // save registers that will be used in RVM, to be restored on return to C    // TODO: I don't think we need to do this: C has no nonvolatile registers on Linux/x86 --dave    // TODO: DAVE    asm.emitPUSH_Reg(JTOC);     asm.emitPUSH_Reg(EBX);             asm.emitPUSH_Reg(S0);             VM_ProcessorLocalState.emitPushProcessor(asm);        // Adjust first param from JNIEnv* to VM_JNIEnvironment.    asm.emitSUB_RegDisp_Imm(EBP, Offset.fromIntSignExtend(2*WORDSIZE), VM_Entrypoints.JNIExternalFunctionsField.getOffsetAsInt());    // copy the arguments in reverse order    VM_TypeReference[] types = method.getParameterTypes();   // does NOT include implicit this or class ptr    int numArguments = types.length;                // number of arguments for this method    Offset argOffset = Offset.fromIntSignExtend(2*WORDSIZE);           // 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, EBP, argOffset.add(WORDSIZE));          asm.emitPUSH_Reg(EBX);        asm.emitMOV_Reg_RegDisp (EBX, EBP, argOffset);          asm.emitPUSH_Reg(EBX);        argOffset=argOffset.add(2*WORDSIZE);      } else {        // Handle 1-word case:        asm.emitMOV_Reg_RegDisp (EBX, EBP, argOffset);          asm.emitPUSH_Reg(EBX);        argOffset=argOffset.add(WORDSIZE);      }    }        // 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 PR from VM_JNIEnvironment     asm.emitMOV_Reg_RegDisp (EBX, EBP, Offset.fromIntSignExtend(2*WORDSIZE));   // pick up arg 0 (from callers frame)    VM_ProcessorLocalState.emitLoadProcessor(asm, EBX, VM_Entrypoints.JNIEnvSavedPRField.getOffset());    // reload JTOC from vitual processor     // NOTE: EDI saved in glue frame is just EDI (opt compiled code uses it as normal non-volatile)    VM_ProcessorLocalState.emitMoveFieldToReg(asm, JTOC,                                              VM_Entrypoints.jtocField.getOffset());    // T0 gets PR.statusField    VM_ProcessorLocalState.emitMoveFieldToReg(asm, T0,                                              VM_Entrypoints.vpStatusField.getOffset());    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_recordField.getOffset());  // T0<-bootrecord addr    asm.emitCALL_RegDisp(T0, VM_Entrypoints.sysVirtualProcessorYieldIPField.getOffset());    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)    VM_ProcessorLocalState.emitCompareAndExchangeField(asm,                                                        VM_Entrypoints.vpStatusField.getOffset(),                                                       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.     // RVM JTOC and PR registers have been restored and EBX contains a pointer to    // the thread's VM_JNIEnvironment.    // 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));       // Retrieve -> preceeding "top" java FP from jniEnv and save in current     // frame of JNIFunction    asm.emitMOV_Reg_RegDisp (S0, EBX, VM_Entrypoints.JNITopJavaFPField.getOffset());          // get offset from current FP and save in hdr of current frame    asm.emitSUB_Reg_Reg (S0, EBP);        asm.emitMOV_RegDisp_Reg (EBP, SAVED_JAVA_FP_OFFSET, S0);    // put framePointer in VP following Jikes RVM conventions.    VM_ProcessorLocalState.emitMoveRegToField(asm,                                              VM_Entrypoints.framePointerField.getOffset(),                                              EBP);    // 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.    // 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  }