asm.emitADDI (T0, -VM_Entrypoints.JNIExternalFunctionsField.getOffsetAsInt(), T0);
asm.emitADDI (T0, Offset.zero().sub(VM_Entrypoints.JNIExternalFunctionsField.getOffset()), T0);
  public static void generateGlueCodeForJNIMethod(VM_Assembler asm, VM_Method mth) {    int offset;    boolean usesVarargs;    int varargAmount = 0;        String mthName = mth.getName().toString();    if ((mthName.startsWith("Call") && mthName.endsWith("Method")) ||        mthName.equals("NewObject"))      usesVarargs = true;    else      usesVarargs = false;    //-#if RVM_WITH_MACH_O_ABI    // Find extra amount of space that needs to be added to the frame    //to hold copies of the vararg values. This calculation is    //overkill since some of these values will be in registers and    //already stored. But then either 3 or 4 of the parameters don't    //show up in the signature anyway (JNIEnvironment, class, method    //id, instance object).    if (usesVarargs) {      VM_TypeReference[] argTypes = mth.getParameterTypes();      int argCount = argTypes.length;          for (int i=0; i<argCount; i++) {        if (argTypes[i].isLongType() || argTypes[i].isDoubleType())           varargAmount += 2 * BYTES_IN_ADDRESS;        else          varargAmount += BYTES_IN_ADDRESS;      }    }    //-#endif          int glueFrameSize = JNI_GLUE_FRAME_SIZE + varargAmount;          asm.emitSTAddrU(FP,-glueFrameSize,FP);     // buy the glue frame    // we may need to save CR in the previous frame also if CR will be used    // CR is to be saved at FP+4 in the previous frame    // Here we check if this is a JNI function that takes the vararg in the ... style    // This includes CallStatic<type>Method, Call<type>Method, CallNonVirtual<type>Method    // For these calls, the vararg starts at the 4th or 5th argument (GPR 6 or 7)    // So, we save the GPR 6-10 and FPR 1-3 in a volatile register save area     // in the glue stack frame so that the JNI function can later repackage the arguments    // based on the parameter types of target method to be invoked.    // (For long argument lists, the additional arguments, have been saved in    // the spill area of the OS caller, and will be retrieved from there.)    //    // If we are compiling such a JNI Function, then emit the code to store    // GPR 4-10 and FPR 1-6 into the volatile save area.    if (usesVarargs) {      //-#if RVM_WITH_POWEROPEN_ABI      offset = STACKFRAME_HEADER_SIZE + 3*BYTES_IN_STACKSLOT;   // skip over slots for GPR 3-5      for (int i = 6; i <= 10; i++ ) {        asm.emitSTAddr(i, offset, FP);        offset+=BYTES_IN_ADDRESS;      }      // store FPRs 1-3 in first 3 slots of volatile FPR save area      for (int i = 1; i <= 3; i++) {        asm.emitSTFD (i, offset, FP);        offset+=BYTES_IN_DOUBLE;      }      //-#elif RVM_WITH_SVR4_ABI       // save all parameter registers      offset = STACKFRAME_HEADER_SIZE + 0;      for (int i=FIRST_OS_PARAMETER_GPR; i<=LAST_OS_PARAMETER_GPR; i++) {        asm.emitSTAddr(i, offset, FP);        offset += BYTES_IN_ADDRESS;      }      for (int i =FIRST_OS_PARAMETER_FPR; i<=LAST_OS_PARAMETER_FPR; i++) {        asm.emitSTFD(i, offset, FP);        offset += BYTES_IN_DOUBLE;      }      //-#elif RVM_WITH_MACH_O_ABI      // save all gpr parameter registers      offset = STACKFRAME_HEADER_SIZE + 0;      for (int i=FIRST_OS_PARAMETER_GPR; i<=LAST_OS_PARAMETER_GPR; i++) {        asm.emitSTAddr(i, offset, FP);        offset += BYTES_IN_ADDRESS;      }      //-#endif    } else {      //-#if RVM_WITH_SVR4_ABI || RVM_WITH_MACH_O_ABI      // adjust register contents (following SVR4 ABI) for normal JNI functions      // especially dealing with long, spills      // number of parameters of normal JNI functions should fix in      // r3 - r12, f1 - f15, + 24 words,       convertParametersFromSVR4ToJava(asm, mth);      //-#endif    }    // Save AIX non-volatile GPRs that will not be saved and restored by RVM.    //    offset = STACKFRAME_HEADER_SIZE + JNI_GLUE_SAVED_VOL_SIZE;   // skip 20 word volatile reg save area    for (int i = FIRST_RVM_RESERVED_NV_GPR; i <=LAST_RVM_RESERVED_NV_GPR; i++) {      asm.emitSTAddr(i, offset, FP);      offset += BYTES_IN_ADDRESS;    }     // set the method ID for the glue frame    // and save the return address in the previous frame    //    asm.emitLVAL(S0, INVISIBLE_METHOD_ID);    asm.emitMFLR(REGISTER_ZERO);    asm.emitSTW(S0, STACKFRAME_METHOD_ID_OFFSET, FP);    asm.emitSTAddr(REGISTER_ZERO, glueFrameSize + STACKFRAME_NEXT_INSTRUCTION_OFFSET, FP);    // Attempt to change the vpStatus of the current Processor to IN_JAVA    //     // on entry T0 = JNIEnv* which is an interior pointer to this thread's VM_JNIEnvironment.    // We first adjust this in place to be a pointer to a VM_JNIEnvironment and then use    // it to acquire PROCESSOR_REGISTER (and JTOC on OSX/Linux).    //    // AIX non volatile gprs 13-16 have been saved & are available (also gprs 11-13 can be used).    // S0=13, S1=14, TI=15, PROCESSOR_REGISTER=16 are available (&have labels) for changing state.    // we leave the passed arguments untouched, unless we are blocked and have to call sysVirtualProcessorYield    // Map from JNIEnv* to VM_JNIEnvironment.    // Must do this outside the loop as we need to do it exactly once.    asm.emitADDI (T0, -VM_Entrypoints.JNIExternalFunctionsField.getOffsetAsInt(), T0);    int retryLoop  = asm.getMachineCodeIndex();    // acquire Jikes RVM PROCESSOR_REGISTER (and JTOC OSX/Linux only).    asm.emitLAddrOffset(PROCESSOR_REGISTER, T0, VM_Entrypoints.JNIEnvSavedPRField.getOffset());    //-#if RVM_WITH_SVR4_ABI || RVM_WITH_MACH_O_ABI    // on AIX JTOC is part of AIX Linkage triplet and this already set by our caller.    // Thus, we only need this load on non-AIX platforms    asm.emitLAddrOffset(JTOC, T0, VM_Entrypoints.JNIEnvSavedJTOCField.getOffset());    //-#endif    asm.emitLVALAddr  (S1, VM_Entrypoints.vpStatusField.getOffset());    asm.emitLWARX (S0, S1, PROCESSOR_REGISTER);               // get status for processor    asm.emitCMPI  (S0, VM_Processor.BLOCKED_IN_NATIVE);       // check if GC in progress, blocked in native mode    VM_ForwardReference frBlocked = asm.emitForwardBC(EQ);    asm.emitLVAL  (S0,  VM_Processor.IN_JAVA);                // S0  <- new state value    asm.emitSTWCXr(S0,  S1, PROCESSOR_REGISTER);              // attempt to change state to IN_JAVA    asm.emitBC    (NE, retryLoop);                            // br if failure -retry lwarx by jumping to label0    VM_ForwardReference frInJava = asm.emitForwardB();        // branch around code to call sysYield    // branch to here if blocked in native, call sysVirtualProcessorYield (pthread yield)    // must save volatile gprs & fprs before the call and restore after    //    frBlocked.resolve(asm);    offset = STACKFRAME_HEADER_SIZE;    // save volatile GPRS 3-10    for (int i = FIRST_OS_PARAMETER_GPR; i <= LAST_OS_PARAMETER_GPR; i++) {      asm.emitSTAddr(i, offset, FP);      offset+=BYTES_IN_ADDRESS;    }    // save volatile FPRS 1-6    for (int i = FIRST_OS_PARAMETER_FPR; i <= LAST_OS_VARARG_PARAMETER_FPR; i++) {      asm.emitSTFD (i, offset, FP);      offset+=BYTES_IN_DOUBLE;    }    asm.emitLAddrToc(S1, VM_Entrypoints.the_boot_recordField.getOffset()); // get boot record address    asm.emitMR   (PROCESSOR_REGISTER, JTOC);                                  // save JTOC so we can restore below    asm.emitLAddrOffset(JTOC, S1, VM_Entrypoints.sysTOCField.getOffset());          // load TOC for syscalls from bootrecord    asm.emitLAddrOffset(KLUDGE_TI_REG, S1, VM_Entrypoints.sysVirtualProcessorYieldIPField.getOffset());  // load addr of function    asm.emitMTLR (KLUDGE_TI_REG);    asm.emitBCLRL();                                                          // call sysVirtualProcessorYield in sys.C    asm.emitMR   (JTOC, PROCESSOR_REGISTER);                                  // restore JTOC    // restore the saved volatile GPRs 3-10 and FPRs 1-6    offset = STACKFRAME_HEADER_SIZE;    // restore volatile GPRS 3-10     for (int i = FIRST_OS_PARAMETER_GPR; i <= LAST_OS_PARAMETER_GPR; i++) {      asm.emitLAddr (i, offset, FP);      offset+=BYTES_IN_ADDRESS;    }    // restore volatile FPRS 1-6      for (int i = FIRST_OS_PARAMETER_FPR; i <= LAST_OS_VARARG_PARAMETER_FPR; i++) {      asm.emitLFD (i, offset, FP);      offset+=BYTES_IN_DOUBLE;    }    asm.emitB (retryLoop);  // br back to label0 to try lwarx again    // NOW_IN_JAVA:    // JTOC, and PR are all as Jikes RVM expects them;    // params are where the Jikes RVM calling conventions expects them.    //     frInJava.resolve(asm);    // get pointer to top java frame from JNIEnv, compute offset from current    // frame pointer (offset to avoid more interior pointers) and save offset    // in this glue frame    //    asm.emitLAddrOffset (S0, T0, VM_Entrypoints.JNITopJavaFPField.getOffset());       // get addr of top java frame from JNIEnv    asm.emitSUBFC (S0, FP, S0);                                                 // S0 <- offset from current FP    // AIX -4, LINUX - 8    asm.emitSTW(S0, glueFrameSize + JNI_GLUE_OFFSET_TO_PREV_JFRAME, FP);  // store offset at end of glue frame    // BRANCH TO THE PROLOG FOR THE JNI FUNCTION    VM_ForwardReference frNormalPrologue = asm.emitForwardBL();    // relative branch and link past the following epilog, to the normal prolog of the method    // the normal epilog of the method will return to the epilog here to pop the glue stack frame    // RETURN TO HERE FROM EPILOG OF JNI FUNCTION    // CAUTION:  START OF EPILOG OF GLUE CODE    // The section of code from here to "END OF EPILOG OF GLUE CODE" is nestled between    // the glue code prolog and the real body of the JNI method.    // T0 & T1 (R3 & R4) or F1 contain the return value from the function - DO NOT USE    // assume: JTOC and PROCESSOR_REG are valid, and all RVM non-volatile     // GPRs and FPRs have been restored.  Our processor state will be  IN_JAVA.    // establish T2 -> current thread's VM_JNIEnvironment, from activeThread field    // of current processor          asm.emitLAddrOffset(T2, PROCESSOR_REGISTER, VM_Entrypoints.activeThreadField.getOffset());   // T2 <- activeThread of PR    asm.emitLAddrOffset(T2, T2, VM_Entrypoints.jniEnvField.getOffset());                         // T2 <- JNIEnvironment     // before returning to C, set pointer to top java frame in JNIEnv, using offset    // saved in this glue frame during transition from C to Java.  GC will use this saved    // frame pointer if it is necessary to do GC with a processors active thread    // stuck (and blocked) in native C, ie. GC starts scanning the threads stack at that frame.        // AIX -4, LINUX -8    asm.emitLInt (T3, glueFrameSize + JNI_GLUE_OFFSET_TO_PREV_JFRAME, FP); // load offset from FP to top java frame    asm.emitADD  (T3, FP, T3);                                    // T3 <- address of top java frame    asm.emitSTAddrOffset(T3, T2, VM_Entrypoints.JNITopJavaFPField.getOffset());     // store TopJavaFP back into JNIEnv    // check to see if this frame address is the sentinel since there    // may be no further Java frame below    asm.emitCMPAddrI(T3, VM_Constants.STACKFRAME_SENTINEL_FP.toInt());    VM_ForwardReference fr4 = asm.emitForwardBC(EQ);    asm.emitLAddr(S0, 0, T3);                   // get fp for caller of prev J to C transition frame    fr4.resolve(asm);    // store current PR into VM_JNIEnvironment; we may have switched PRs while in Java mode.    asm.emitSTAddrOffset(PROCESSOR_REGISTER, T2, VM_Entrypoints.JNIEnvSavedPRField.getOffset());    // change the state of the VP to IN_NATIVE.    //    asm.emitLVAL (S0,  VM_Processor.IN_NATIVE);    asm.emitSTWoffset  (S0, PROCESSOR_REGISTER, VM_Entrypoints.vpStatusField.getOffset());    // Restore those AIX nonvolatile registers saved in the prolog above    // Here we only save & restore ONLY those registers not restored by RVM    //    offset = STACKFRAME_HEADER_SIZE + JNI_GLUE_SAVED_VOL_SIZE;   // skip 20 word volatile reg save area    for (int i = FIRST_RVM_RESERVED_NV_GPR; i <=LAST_RVM_RESERVED_NV_GPR; i++) {      asm.emitLAddr (i, offset, FP);                     // 4 instructions      offset += BYTES_IN_ADDRESS;    }    // pop frame    asm.emitADDI(FP, glueFrameSize, FP);    // load return address & return to caller    // T0 & T1 (or F1) should still contain the return value    //    asm.emitLAddr(T2, STACKFRAME_NEXT_INSTRUCTION_OFFSET, FP);    asm.emitMTLR(T2);    asm.emitBCLR (); // branch always, through link register    // END OF EPILOG OF GLUE CODE; rest of method generated by VM_Compiler from bytecodes of method in VM_JNIFunctions    frNormalPrologue.resolve(asm);  } 