asm.emitSTW  (T3, VM_Entrypoints.JNIRefsTopField.getOffset(), S0);
asm.emitSTW  (T3, VM_Entrypoints.JNIRefsTopField.getOffsetAsInt(), S0);
  public static synchronized VM_CompiledMethod compile (VM_NativeMethod method) {    VM_JNICompiledMethod cm = (VM_JNICompiledMethod)VM_CompiledMethods.createCompiledMethod(method, VM_CompiledMethod.JNI);    int compiledMethodId = cm.getId();    VM_Assembler asm    = new VM_Assembler(0);    int frameSize       = VM_Compiler.getFrameSize(method);    VM_Class klass      = method.getDeclaringClass();    /* initialization */    if (VM.VerifyAssertions) VM._assert(T3 <= LAST_VOLATILE_GPR);           // need 4 gp temps    if (VM.VerifyAssertions) VM._assert(F3 <= LAST_VOLATILE_FPR);           // need 4 fp temps    if (VM.VerifyAssertions) VM._assert(S0 < S1 && S1 <= LAST_SCRATCH_GPR); // need 2 scratch    Address nativeIP  = method.getNativeIP();    Address nativeTOC = method.getNativeTOC();    // NOTE:  this must be done before the condition VM_Thread.hasNativeStackFrame() become true    // so that the first Java to C transition will be allowed to resize the stack    // (currently, this is true when the JNIRefsTop index has been incremented from 0)    asm.emitNativeStackOverflowCheck(frameSize + 14);   // add at least 14 for C frame (header + spill)    int parameterAreaSize = method.getParameterWords() << LOG_BYTES_IN_STACKSLOT;   // number of bytes of arguments    // save return address in caller frame    asm.emitMFLR(REGISTER_ZERO);    asm.emitSTAddr(REGISTER_ZERO, STACKFRAME_NEXT_INSTRUCTION_OFFSET, FP);            //-#if RVM_WITH_SVR4_ABI || RVM_WITH_MACH_O_ABI    // buy mini frame (2)    asm.emitSTAddrU   (FP, -JNI_SAVE_AREA_SIZE, FP);    asm.emitLVAL  (S0, compiledMethodId);                // save jni method id at mini frame (2)    asm.emitSTW   (S0, STACKFRAME_METHOD_ID_OFFSET, FP);    // buy mini frame (1), the total size equals to frameSize    asm.emitSTAddrU   (FP, -frameSize + JNI_SAVE_AREA_SIZE, FP);    //-#endif            //-#if RVM_WITH_POWEROPEN_ABI    asm.emitSTAddrU   (FP,  -frameSize, FP);             // get transition frame on stack    asm.emitLVAL  (S0, compiledMethodId);                // save jni method id    asm.emitSTW   (S0, STACKFRAME_METHOD_ID_OFFSET, FP);    //-#endif    // establish S1 -> VM_Thread, S0 -> threads JNIEnv structure          asm.emitLAddr(S1, VM_Entrypoints.activeThreadField.getOffset(), PROCESSOR_REGISTER);    asm.emitLAddr(S0, VM_Entrypoints.jniEnvField.getOffset(), S1);    // save the PR register in the JNIEnvironment object for possible calls back into Java    asm.emitSTAddr(PROCESSOR_REGISTER, VM_Entrypoints.JNIEnvSavedPRField.getOffset(), S0);           // save the JNIEnvironment in the stack frame so we can use it to acquire the PR    // when we return from native code.    asm.emitSTAddr (S0, frameSize - JNI_ENV_OFFSET, FP);  // save PR in frame      // save current frame pointer in JNIEnv, JNITopJavaFP, which will be the frame    // to start scanning this stack during GC, if top of stack is still executing in C    //-#if RVM_WITH_SVR4_ABI || RVM_WITH_MACH_O_ABI    // for Linux, save mini (2) frame pointer, which has method id    asm.emitLAddr (PROCESSOR_REGISTER, 0, FP);    asm.emitSTAddr(PROCESSOR_REGISTER, VM_Entrypoints.JNITopJavaFPField.getOffset(), S0);    //-#elif RVM_WITH_POWEROPEN_ABI    asm.emitSTAddr(FP, VM_Entrypoints.JNITopJavaFPField.getOffset(), S0);               //-#endif            // save the RVM nonvolatile registers, to be scanned by GC stack mapper    // remember to skip past the saved JTOC  by starting with offset = JNI_RVM_NONVOLATILE_OFFSET    //    for (int i = LAST_NONVOLATILE_GPR, offset = JNI_RVM_NONVOLATILE_OFFSET;         i >= FIRST_NONVOLATILE_GPR; --i, offset+=BYTES_IN_STACKSLOT) {      asm.emitSTAddr(i, frameSize - offset, FP);    }    // clear the GC flag on entry to native code    asm.emitLVAL(PROCESSOR_REGISTER,0);          // use PR as scratch    asm.emitSTW(PROCESSOR_REGISTER, frameSize-JNI_GC_FLAG_OFFSET, FP);      // generate the code to map the parameters to OS convention and add the    // second parameter (either the "this" ptr or class if a static method).    // The JNI Function ptr first parameter is set before making the call    // by the out of line machine code we invoke below.    // Opens a new frame in the JNIRefs table to register the references.    // Assumes S0 set to JNIEnv, kills KLUDGE_TI_REG, S1 & PROCESSOR_REGISTER    // On return, S0 still contains JNIEnv    storeParameters(asm, frameSize, method, klass);            // Get address of out_of_line prolog into S1, before setting TOC reg.    asm.emitLAddr (S1, VM_Entrypoints.invokeNativeFunctionInstructionsField.getOffset(), JTOC);    asm.emitMTCTR (S1);    // set the TOC and IP for branch to out_of_line code    asm.emitLVALAddr (JTOC,  nativeTOC);    asm.emitLVALAddr (S1,    nativeIP);    // go to VM_OutOfLineMachineCode.invokeNativeFunctionInstructions    // It will change the Processor status to "in_native" and transfer to the native code.      // On return it will change the state back to "in_java" (waiting if blocked).    //    // The native address entrypoint is in register S1    // The native TOC has been loaded into the TOC register    // S0 still points to threads JNIEnvironment    //    asm.emitBCCTRL();    // check if GC has occurred, If GC did not occur, then     // VM NON_VOLATILE regs were restored by OS and are valid.  If GC did occur    // objects referenced by these restored regs may have moved, in this case we    // restore the nonvolatile registers from our save area,    // where any object references would have been relocated during GC.    // use T2 as scratch (not needed any more on return from call)    //    asm.emitLWZ(T2, frameSize - JNI_GC_FLAG_OFFSET, FP);    asm.emitCMPI(T2,0);    VM_ForwardReference fr1 = asm.emitForwardBC(EQ);    for (int i = LAST_NONVOLATILE_GPR, offset = JNI_RVM_NONVOLATILE_OFFSET;         i >= FIRST_NONVOLATILE_GPR; --i, offset+=BYTES_IN_STACKSLOT) {      asm.emitLAddr(i, frameSize - offset, FP);    }    fr1.resolve(asm);    asm.emitLAddr(S0, VM_Entrypoints.activeThreadField.getOffset(), PROCESSOR_REGISTER);  // S0 holds thread pointer    // reestablish S0 to hold pointer to VM_JNIEnvironment    asm.emitLAddr(S0, VM_Entrypoints.jniEnvField.getOffset(), S0);           // pop jrefs frame off the JNIRefs stack, "reopen" the previous top jref frame    // use S1 as scratch, also use T2, T3 for scratch which are no longer needed    asm.emitLAddr(S1, VM_Entrypoints.JNIRefsField.getOffset(), S0);          // load base of JNIRefs array    asm.emitLInt (T2, VM_Entrypoints.JNIRefsSavedFPField.getOffset(), S0);   // get saved offset for JNIRefs frame ptr previously pushed onto JNIRefs array    asm.emitADDI (T3, -BYTES_IN_STACKSLOT, T2);                                    // compute offset for new TOP    asm.emitSTW  (T3, VM_Entrypoints.JNIRefsTopField.getOffset(), S0);       // store new offset for TOP into JNIEnv    asm.emitLIntX(T2, S1, T2);                                    // retrieve the previous frame ptr    asm.emitSTW  (T2, VM_Entrypoints.JNIRefsSavedFPField.getOffset(), S0);   // store new offset for JNIRefs frame ptr into JNIEnv    // Restore the return value R3-R4 saved in the glue frame spill area before the migration    if (VM.BuildFor64Addr) {      asm.emitLD(T0, NATIVE_FRAME_HEADER_SIZE, FP);    } else {      asm.emitLWZ(T0, NATIVE_FRAME_HEADER_SIZE, FP);      asm.emitLWZ(T1, NATIVE_FRAME_HEADER_SIZE+BYTES_IN_STACKSLOT, FP);    }          // if the the return type is a reference, the native C is returning a jref    // which is a byte offset from the beginning of the threads JNIRefs stack/array    // of the corresponding ref.  In this case, emit code to replace the returned    // offset (in R3) with the ref from the JNIRefs array    VM_TypeReference returnType = method.getReturnType();    if (returnType.isReferenceType()) {      // use returned offset to load ref from JNIRefs into R3      asm.emitLAddrX (T0, S1, T0);         // S1 is still the base of the JNIRefs array    }    // pop the glue stack frame, restore the Java caller frame    asm.emitADDI (FP,  +frameSize, FP);              // remove linkage area    // C return value is already where caller expected it (T0/T1 or F0)    // So, just restore the return address to the link register.    asm.emitLAddr(REGISTER_ZERO, STACKFRAME_NEXT_INSTRUCTION_OFFSET, FP);     asm.emitMTLR (REGISTER_ZERO);                           // restore return address    // CHECK EXCEPTION AND BRANCH TO ATHROW CODE OR RETURN NORMALLY    asm.emitLAddr (T2, VM_Entrypoints.JNIPendingExceptionField.getOffset(), S0);   // get pending exception from JNIEnv    asm.emitLVAL  (T3, 0);                   // get a null value to compare    asm.emitSTAddr(T3, VM_Entrypoints.JNIPendingExceptionField.getOffset(), S0); // clear the current pending exception    asm.emitCMPAddr(T2, T3);    VM_ForwardReference fr3 = asm.emitForwardBC(NE);    asm.emitBCLR();                             // if no pending exception, proceed to return to caller    fr3.resolve(asm);    // An exception is pending, deliver the exception to the caller    // as if executing an athrow in the caller    // at the location of the call to the native method    asm.emitLAddrToc(T3, VM_Entrypoints.athrowMethod.getOffset());    asm.emitMTCTR(T3);                         // point LR to the exception delivery code    asm.emitMR (T0, T2);                       // copy the saved exception to T0    asm.emitBCCTR();                           // then branch to the exception delivery code, does not return    VM_MachineCode machineCode = asm.makeMachineCode();    cm.compileComplete(machineCode.getInstructions());    return cm;  } 