asm.emitLWZ(TI, VM_Entrypoints.JNIRefsTopField.getOffset(), S0);
asm.emitLInt(TI, VM_Entrypoints.JNIRefsTopField.getOffset(), S0);
  static void storeParametersForLinux(VM_Assembler asm,				      int frameSize,				      VM_Method method,				      VM_Class klass) {    int nextAIXArgReg, nextAIXArgFloatReg, nextVMArgReg, nextVMArgFloatReg;         // offset to the spill area in the callee (Linux frame)	// remove     int spillOffsetAIX = NATIVE_FRAME_HEADER_SIZE;     // offset to the spill area in the caller (RVM frame), relative to    // the callee's FP    int spillOffsetVM = frameSize + STACKFRAME_HEADER_SIZE;    // does NOT include implicit this or class ptr    VM_TypeReference[] types = method.getParameterTypes();     // number of arguments for this method    int numArguments = types.length;         // Set up the Reference table for GC    // PR <- JREFS array base    asm.emitLAddr(PROCESSOR_REGISTER, VM_Entrypoints.JNIRefsField.getOffset(), S0);    // TI <- JREFS current top     asm.emitLWZ(TI, VM_Entrypoints.JNIRefsTopField.getOffset(), S0);   // JREFS offset for current TOP     asm.emitADD(TI, PROCESSOR_REGISTER, TI);                // convert into address    // TODO - count number of refs    // TODO - emit overflow check for JNIRefs array        // start a new JNIRefs frame on each transition from Java to native C    // push current SavedFP ptr onto top of JNIRefs stack (use available S1 reg as a temp)    // and make current TOP the new savedFP    //    asm.emitLWZ  (S1, VM_Entrypoints.JNIRefsSavedFPField.getOffset(), S0);    asm.emitSTWU (S1, 4, TI);                           // push prev frame ptr onto JNIRefs array	    asm.emitSUBFC(S1, PROCESSOR_REGISTER, TI);           // compute offset for new TOP    asm.emitSTW  (S1, VM_Entrypoints.JNIRefsSavedFPField.getOffset(), S0);  // save new TOP as new frame ptr in JNIEnv    // for static methods: caller has placed args in r3,r4,...     // for non-static methods:"this" ptr is in r3, and args start in r4,r5,...    //     // for static methods:                for nonstatic methods:           //  Java caller     AIX callee         Java caller     AIX callee        //  -----------     ----------	    -----------     ----------      //  spill = arg11 -> new spill	    spill = arg11 -> new spill      //  spill = arg10 -> new spill	    spill = arg10 -> new spill      // 				            spill = arg9  -> new spill      //    R12 = arg9  -> new spill	                                    //    R11 = arg8  -> new spill	      R12 = arg8  -> new spill      //    R10 = arg7  -> new spill	      R11 = arg7  -> new spill      //    R9  = arg6  -> new spill	      R10 = arg6  -> new spill      // 								       //    R8  = arg5  -> R10                  R9  = arg5  -> R10             //    R7  = arg4  -> R9		      R8  = arg4  -> R9              //    R6  = arg3  -> R8		      R7  = arg3  -> R8              //    R5  = arg2  -> R7		      R6  = arg2  -> R7              //    R4  = arg1  -> R6		      R5  = arg1  -> R6              //    R3  = arg0  -> R5		      R4  = arg0  -> R5              //                   R4 = class           R3  = this  -> R4             // 	                 R3 = JNIenv                         R3 = JNIenv    //    // if the number of args in GPR does not exceed R11, then we can use R12 as scratch     //   to move the args    // if the number of args in GPR exceed R12, then we need to save R12 first to make     //   room for a scratch register    // if the number of args in FPR does not exceed F12, then we can use F13 as scratch    nextAIXArgFloatReg = FIRST_OS_PARAMETER_FPR;    nextVMArgFloatReg  = FIRST_VOLATILE_FPR;    nextAIXArgReg      = FIRST_OS_PARAMETER_GPR + 2;   // 1st reg = JNIEnv, 2nd reg = class    if ( method.isStatic() ) {      nextVMArgReg = FIRST_VOLATILE_GPR;                  } else {      nextVMArgReg = FIRST_VOLATILE_GPR+1;            // 1st reg = this, to be processed separately    }    // The loop below assumes the following relationship:    if (VM.VerifyAssertions) VM._assert(FIRST_OS_PARAMETER_FPR==FIRST_VOLATILE_FPR);    if (VM.VerifyAssertions) VM._assert(LAST_OS_PARAMETER_FPR<=LAST_VOLATILE_FPR);    if (VM.VerifyAssertions) VM._assert(FIRST_OS_PARAMETER_GPR==FIRST_VOLATILE_GPR);    if (VM.VerifyAssertions) VM._assert(LAST_OS_PARAMETER_GPR<=LAST_VOLATILE_GPR);    // create one VM_Assembler object for each argument    // This is needed for the following reason:    //   -2 new arguments are added in front for native methods, so the normal arguments    //    need to be shifted down in addition to being moved    //   -to avoid overwriting each other, the arguments must be copied in reverse order    //   -the analysis for mapping however must be done in forward order    //   -the moving/mapping for each argument may involve a sequence of 1-3 instructions     //    which must be kept in the normal order    // To solve this problem, the instructions for each argument is generated in its    // own VM_Assembler in the forward pass, then in the reverse pass, each VM_Assembler    // emist the instruction sequence and copies it into the main VM_Assembler    VM_Assembler[] asmForArgs = new VM_Assembler[numArguments];    for (int arg = 0; arg < numArguments; arg++) {            asmForArgs[arg] = new VM_Assembler(0);      VM_Assembler asmArg = asmForArgs[arg];      // For 32-bit float arguments, must be converted to      // double       //      if (types[arg].isFloatType() || types[arg].isDoubleType()) {	boolean is32bits = types[arg].isFloatType();	       	// 1. check the source, the value will be in srcVMArg	int srcVMArg; // scratch fpr	if (nextVMArgFloatReg <= LAST_VOLATILE_FPR) {	  srcVMArg = nextVMArgFloatReg;	  nextVMArgFloatReg ++;	} else {	  srcVMArg = FIRST_SCRATCH_FPR;	  // VM float reg is in spill area	  if (is32bits) {	    asmArg.emitLFS(srcVMArg, spillOffsetVM, FP);	    spillOffsetVM += 4;	  } else {	    asmArg.emitLFD(srcVMArg, spillOffsetVM, FP);	    spillOffsetVM += 8;	  }	}  			// 2. check the destination, 	if (nextAIXArgFloatReg <= LAST_OS_PARAMETER_FPR) {	  // leave it there	  nextAIXArgFloatReg ++;	} else {	  // spill it, round the spill address to 8	  // assuming FP is aligned to 8	  spillOffsetAIX = (spillOffsetAIX + 7) & -8;	  	  asmArg.emitSTFD(srcVMArg, spillOffsetAIX, FP);	  spillOffsetAIX += 8; }	// for 64-bit long arguments      } else if (types[arg].isLongType()) {	// handle AIX first	boolean dstSpilling;	int regOrSpilling = -1;  // it is register number or spilling offset	// 1. check if Linux register > 9	if (nextAIXArgReg > (LAST_OS_PARAMETER_GPR - 1)) {	  // goes to spilling area	  dstSpilling = true;	  	  // NOTE: following adjustment is not stated in SVR4 ABI, but 	  // implemented in GCC	  // -- Feng	  nextAIXArgReg = LAST_OS_PARAMETER_GPR + 1;	  	  // compute spilling offset	  spillOffsetAIX = (spillOffsetAIX + 7) & -8;	  regOrSpilling = spillOffsetAIX;	  spillOffsetAIX += 8;	} else {	  // use registers	  dstSpilling = false;	  // rounds to odd	  nextAIXArgReg += (nextAIXArgReg + 1) & 0x01; // if gpr is even, gpr += 1	  regOrSpilling = nextAIXArgReg;	  nextAIXArgReg += 2;	}		// handle RVM source	if (nextVMArgReg < LAST_VOLATILE_GPR) {	  // both parts in registers	  if (dstSpilling) {	    asmArg.emitSTW(nextVMArgReg+1, regOrSpilling+4, FP);	    asmArg.emitSTW(nextVMArgReg, regOrSpilling, FP);	  } else {	    asmArg.emitMR(regOrSpilling+1, nextVMArgReg+1);	    asmArg.emitMR(regOrSpilling, nextVMArgReg);	  }	  // advance register counting, Linux register number	  // already advanced 	  nextVMArgReg += 2;	} else if (nextVMArgReg == LAST_VOLATILE_GPR) {	  // VM striding	  if (dstSpilling) {	    asmArg.emitLWZ(0, spillOffsetVM, FP);	    asmArg.emitSTW(0, regOrSpilling+4, FP);	    asmArg.emitSTW(nextVMArgReg, regOrSpilling, FP);	  } else {	    asmArg.emitLWZ(regOrSpilling + 1, spillOffsetVM, FP);	    asmArg.emitMR(regOrSpilling, nextVMArgReg);	  }	  // advance spillOffsetVM and nextVMArgReg	  nextVMArgReg ++;	  spillOffsetVM += 4;	} else if (nextVMArgReg > LAST_VOLATILE_GPR) {	  if (dstSpilling) {	    asmArg.emitLFD(FIRST_SCRATCH_FPR, spillOffsetVM, FP);	    asmArg.emitSTFD(FIRST_SCRATCH_FPR, regOrSpilling, FP);	  } else {	    // this shouldnot happen, VM spills, AIX has registers	    asmArg.emitLWZ(regOrSpilling + 1, spillOffsetVM+4, FP);	    asmArg.emitLWZ(regOrSpilling, spillOffsetVM, FP);	  }		  spillOffsetVM += 8;	}      } else if (types[arg].isReferenceType() ) {		// For reference type, replace with handlers before passing to AIX	int srcreg, dstreg;	if (nextVMArgReg <= LAST_VOLATILE_GPR) {	  srcreg = nextVMArgReg++;	} else {	  srcreg = 0;	  asmArg.emitLWZ(srcreg, spillOffsetVM, FP);	  spillOffsetVM += 4;	}	asmArg.emitSTWU(srcreg, 4, TI);		if (nextAIXArgReg <= LAST_OS_PARAMETER_GPR) {	  asmArg.emitSUBFC(nextAIXArgReg++, PROCESSOR_REGISTER, TI);	} else {	  asmArg.emitSUBFC(0, PROCESSOR_REGISTER, TI);	  asmArg.emitSTW(0, spillOffsetAIX, FP);	  spillOffsetAIX += 4;	}      } else {	// For all other types: int, short, char, byte, boolean	// (1a) fit in AIX register, move the register	if (nextAIXArgReg<=LAST_OS_PARAMETER_GPR) {	  asmArg.emitMR(nextAIXArgReg++, nextVMArgReg++);	}	// (1b) spill AIX register, but still fit in VM register	else if (nextVMArgReg<=LAST_VOLATILE_GPR) {	  asmArg.emitSTW(nextVMArgReg++, spillOffsetAIX, FP);	  spillOffsetAIX+=4;	} else {	  // (1c) spill VM register	  asmArg.emitLWZ(0,spillOffsetVM, FP);        // retrieve arg from VM spill area	  asmArg.emitSTW(0, spillOffsetAIX, FP);	  spillOffsetVM+=4;	  spillOffsetAIX+=4;	}      }    }        // Append the code sequences for parameter mapping     // to the current machine code in reverse order    // so that the move does not overwrite the parameters    for (int arg = numArguments-1; arg >= 0; arg--) {      VM_MachineCode codeForArg = asmForArgs[arg].makeMachineCode();      asm.appendInstructions(codeForArg.getInstructions());    }    // Now add the 2 new JNI parameters:  JNI environment and Class or "this" object        // if static method, append ref for class, else append ref for "this"    // and pass offset in JNIRefs array in r4 (as second arg to called native code)    int secondAIXVolatileReg = FIRST_OS_PARAMETER_GPR + 1;	if ( method.isStatic() ) {      klass.getClassForType();     // ensure the Java class object is created      // JTOC saved above in JNIEnv is still valid, used by following emitLWZtoc      asm.emitLAddrToc(secondAIXVolatileReg, klass.getTibOffset() ); // r4 <- class TIB ptr from jtoc      asm.emitLWZ  (secondAIXVolatileReg, 0, secondAIXVolatileReg);                  // r4 <- first TIB entry == -> class object      asm.emitLWZ  (secondAIXVolatileReg, VM_Entrypoints.classForTypeField.getOffset(), secondAIXVolatileReg); // r4 <- java Class for this VM_Class      asm.emitSTWU (secondAIXVolatileReg, 4, TI );                 // append class ptr to end of JNIRefs array      asm.emitSUBFC  (secondAIXVolatileReg, PROCESSOR_REGISTER, TI );  // pass offset in bytes    } else {      asm.emitSTWU (FIRST_OS_PARAMETER_GPR, 4, TI );                 // append this ptr to end of JNIRefs array      asm.emitSUBFC  (secondAIXVolatileReg, PROCESSOR_REGISTER, TI );  // pass offset in bytes    }        // store the new JNIRefs array TOP back into JNIEnv	    asm.emitSUBFC(TI, PROCESSOR_REGISTER, TI );     // compute offset for the current TOP    asm.emitSTW(TI, VM_Entrypoints.JNIRefsTopField.getOffset(), S0);  }