asmArg.emitSTAddr(nextVMArgReg++, spillOffsetAIX, FP); spillOffsetAIX+=BYTES_IN_STACKSLOT;
asmArg.emitSTAddr(nextVMArgReg++, spillOffsetAIX - BYTES_IN_ADDRESS, FP);
  private static void storeParametersForAIX(VM_Assembler asm, 					    int frameSize, 					    VM_Method method, VM_Class klass) {    int nextAIXArgReg, nextAIXArgFloatReg, nextVMArgReg, nextVMArgFloatReg;         // offset to the spill area in the callee (AIX frame):    // skip past the 2 arguments to be added in front:  JNIenv and class or object pointer    int spillOffsetAIX = NATIVE_FRAME_HEADER_SIZE + 2*BYTES_IN_STACKSLOT;    // offset to the spill area in the caller (RVM frame), relative to the callee's FP    int spillOffsetVM = frameSize + STACKFRAME_HEADER_SIZE;    VM_TypeReference[] types = method.getParameterTypes();   // does NOT include implicit this or class ptr    int numArguments = types.length;                // number of arguments for this method        // 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.emitLInt(KLUDGE_TI_REG, VM_Entrypoints.JNIRefsTopField.getOffset(), S0);   // JREFS offset for current TOP     asm.emitADD(KLUDGE_TI_REG, PROCESSOR_REGISTER, KLUDGE_TI_REG);                // 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.emitLInt  (S1, VM_Entrypoints.JNIRefsSavedFPField.getOffset(), S0);    asm.emitSTWU (S1, BYTES_IN_ADDRESS, KLUDGE_TI_REG);                           // push prev frame ptr onto JNIRefs array	    asm.emitSUBFC(S1, PROCESSOR_REGISTER, KLUDGE_TI_REG);          // 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      //  spill = arg9  -> new spill	                                    //  spill = arg8  -> new spill	    spill = arg8  -> new spill      //    R10 = arg7  -> new spill	    spill = 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    //    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++) {      boolean mustSaveFloatToSpill;      asmForArgs[arg] = new VM_Assembler(0);      VM_Assembler asmArg = asmForArgs[arg];      // For 32-bit float arguments      //      if (types[arg].isFloatType()) {	// Side effect of float arguments on the GPR's	// (1a) reserve one GPR for each float if it is available	if (nextAIXArgReg<=LAST_OS_PARAMETER_GPR) {	  nextAIXArgReg++;	  mustSaveFloatToSpill = false;	} else {	  // (1b) if GPR has spilled, store the float argument in the callee spill area	  // regardless of whether the FPR has spilled or not	  mustSaveFloatToSpill = true;	}	// Check if the args need to be moved	// (2a) leave those in FPR[1:13] as is unless the GPR has spilled	if (nextVMArgFloatReg<=LAST_OS_PARAMETER_FPR) {	  if (mustSaveFloatToSpill) {	    asmArg.emitSTFS(nextVMArgFloatReg, spillOffsetAIX, FP); 	  }	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	  nextAIXArgFloatReg++;	  nextVMArgFloatReg++;  	} else if (nextVMArgFloatReg<=LAST_VOLATILE_FPR) {	  // (2b) run out of FPR in AIX, but still have 2 more FPR in VM,	  // so FPR[14:15] goes to the callee spill area	  asmArg.emitSTFS(nextVMArgFloatReg, spillOffsetAIX, FP);	  nextVMArgFloatReg++;	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	} else {	  // (2c) run out of FPR in VM, now get the remaining args from the caller spill area 	  // and move them into the callee spill area	  spillOffsetVM+=BYTES_IN_STACKSLOT;	  asmArg.emitLFS(FIRST_SCRATCH_FPR, spillOffsetVM - BYTES_IN_FLOAT, FP); //Kris Venstermans: Attention, different calling convention !!	  asmArg.emitSTFS(FIRST_SCRATCH_FPR, spillOffsetAIX, FP);	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	}      } else if (types[arg].isDoubleType()) {	// For 64-bit float arguments         if (VM.BuildFor64Addr) {	  // Side effect of float arguments on the GPR's	  // (1a) reserve one GPR for double	  if (nextAIXArgReg<=LAST_OS_PARAMETER_GPR) {	    nextAIXArgReg++;	    mustSaveFloatToSpill = false;	  } else {	    // (1b) if GPR has spilled, store the float argument in the callee spill area	    // regardless of whether the FPR has spilled or not	    mustSaveFloatToSpill = true;	  }	} else {	  // Side effect of float arguments on the GPR's	  // (1a) reserve two GPR's for double	  if (nextAIXArgReg<=LAST_OS_PARAMETER_GPR-1) {	    nextAIXArgReg+=2;	    mustSaveFloatToSpill = false;	  } else {	    // if only one GPR is left, reserve it anyway although it won't be used	    if (nextAIXArgReg<=LAST_OS_PARAMETER_GPR)	      nextAIXArgReg++;	    mustSaveFloatToSpill = true;	  }	}	// Check if the args need to be moved	// (2a) leave those in FPR[1:13] as is unless the GPR has spilled	if (nextVMArgFloatReg<=LAST_OS_PARAMETER_FPR) {	  if (mustSaveFloatToSpill) {	    asmArg.emitSTFD(nextVMArgFloatReg, spillOffsetAIX, FP); 	  }	  spillOffsetAIX+=BYTES_IN_DOUBLE; //Kris Venstermans: equals 2 slots on 32-bit platforms and 1 slot on 64-bit platform	  nextAIXArgFloatReg++;	  nextVMArgFloatReg++;  	} else if (nextVMArgFloatReg<=LAST_VOLATILE_FPR) {	  // (2b) run out of FPR in AIX, but still have 2 more FPR in VM,	  // so FPR[14:15] goes to the callee spill area	  asmArg.emitSTFD(nextVMArgFloatReg, spillOffsetAIX, FP);	  nextVMArgFloatReg++;	  spillOffsetAIX+=BYTES_IN_DOUBLE; 	} else {	  // (2c) run out of FPR in VM, now get the remaining args from the caller spill area 	  // and move them into the callee spill area	  asmArg.emitLFD(FIRST_SCRATCH_FPR, spillOffsetVM , FP);	  asmArg.emitSTFD(FIRST_SCRATCH_FPR, spillOffsetAIX, FP);	  spillOffsetAIX+= BYTES_IN_DOUBLE;	  spillOffsetVM+=BYTES_IN_DOUBLE;	}      } else if (VM.BuildFor32Addr && types[arg].isLongType()) {	// For 64-bit int arguments on 32-bit platforms	//	// (1a) fit in AIX register, move the pair	if (nextAIXArgReg<=LAST_OS_PARAMETER_GPR-1) {	  asmArg.emitMR(nextAIXArgReg+1, nextVMArgReg+1);  // move lo-word first	  asmArg.emitMR(nextAIXArgReg, nextVMArgReg);      // so it doesn't overwritten	  nextAIXArgReg+=2;	  nextVMArgReg+=2;	  spillOffsetAIX+=2*BYTES_IN_STACKSLOT;	} else if (nextAIXArgReg==LAST_OS_PARAMETER_GPR &&	  nextVMArgReg<=LAST_VOLATILE_GPR-1) {	  // (1b) fit in VM register but straddle across AIX register/spill	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	  asmArg.emitSTW(nextVMArgReg+1, spillOffsetAIX, FP);   // move lo-word first	  spillOffsetAIX+=BYTES_IN_STACKSLOT;                    // so it doesn't overwritten	  asmArg.emitMR(nextAIXArgReg, nextVMArgReg);	  nextAIXArgReg+=2;	  nextVMArgReg+=2;	  	} else if (nextAIXArgReg>LAST_OS_PARAMETER_GPR &&		   nextVMArgReg<=LAST_VOLATILE_GPR-1) {	  // (1c) fit in VM register, spill in AIX without straddling register/spill	  asmArg.emitSTW(nextVMArgReg++, spillOffsetAIX, FP);	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	  asmArg.emitSTW(nextVMArgReg++, spillOffsetAIX, FP);	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	} else if (nextVMArgReg==LAST_VOLATILE_GPR) {	  // (1d) split across VM/spill, spill in AIX	  asmArg.emitSTW(nextVMArgReg++, spillOffsetAIX, FP);	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	  asmArg.emitLWZ(REGISTER_ZERO, spillOffsetVM , FP);	  asmArg.emitSTW(REGISTER_ZERO, spillOffsetAIX, FP);	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	  spillOffsetVM+=BYTES_IN_STACKSLOT;	} else {	  // (1e) spill both in VM and AIX	  asmArg.emitLFD(FIRST_SCRATCH_FPR, spillOffsetVM, FP);	  asmArg.emitSTFD(FIRST_SCRATCH_FPR, spillOffsetAIX, FP);	  spillOffsetAIX+=2*BYTES_IN_STACKSLOT;	  spillOffsetVM+=2*BYTES_IN_STACKSLOT;	}      } else if (types[arg].isReferenceType() ) {		// For reference type, replace with handlers before passing to AIX	//		// (1a) fit in AIX register, move the register	if (nextAIXArgReg<=LAST_OS_PARAMETER_GPR) {	  asmArg.emitSTAddrU(nextVMArgReg++, BYTES_IN_ADDRESS, KLUDGE_TI_REG);          // append ref to end of JNIRefs array	  asmArg.emitSUBFC(nextAIXArgReg++, PROCESSOR_REGISTER, KLUDGE_TI_REG);  // pass offset in bytes of jref	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	} else if (nextVMArgReg<=LAST_VOLATILE_GPR) {	  // (1b) spill AIX register, but still fit in VM register	  asmArg.emitSTAddrU(nextVMArgReg++, BYTES_IN_ADDRESS, KLUDGE_TI_REG);    // append ref to end of JNIRefs array	  asmArg.emitSUBFC(REGISTER_ZERO, PROCESSOR_REGISTER, KLUDGE_TI_REG);  // compute offset in bytes for jref	  asmArg.emitSTAddr(REGISTER_ZERO, spillOffsetAIX, FP);       // spill into AIX frame	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	} else {	  // (1c) spill VM register	  asmArg.emitLAddr(REGISTER_ZERO, spillOffsetVM , FP);        // retrieve arg from VM spill area	  asmArg.emitSTAddrU(REGISTER_ZERO, BYTES_IN_ADDRESS, KLUDGE_TI_REG);  // append ref to end of JNIRefs array	  asmArg.emitSUBFC(REGISTER_ZERO, PROCESSOR_REGISTER, KLUDGE_TI_REG);  // compute offset in bytes for jref	  asmArg.emitSTAddr(REGISTER_ZERO, spillOffsetAIX, FP);       // spill into AIX frame	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	  spillOffsetVM+=BYTES_IN_STACKSLOT;	}      } else { 	// For all other types: int, short, char, byte, boolean ( and long on 64-bit platform)	// (1a) fit in AIX register, move the register	if (nextAIXArgReg<=LAST_OS_PARAMETER_GPR) {	  asmArg.emitMR(nextAIXArgReg++, nextVMArgReg++);	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	}	// (1b) spill AIX register, but still fit in VM register	else if (nextVMArgReg<=LAST_VOLATILE_GPR) {	  asmArg.emitSTAddr(nextVMArgReg++, spillOffsetAIX, FP);	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	} else {	  // (1c) spill VM register	  asmArg.emitLAddr(REGISTER_ZERO,spillOffsetVM, FP);        // retrieve arg from VM spill area	  asmArg.emitSTAddr(REGISTER_ZERO, spillOffsetAIX, FP);	  spillOffsetAIX+=BYTES_IN_STACKSLOT;	  spillOffsetVM+=BYTES_IN_STACKSLOT;	}      }    }        // 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)    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( 4, klass.getTibOffset() ); // r4 <- class TIB ptr from jtoc      asm.emitLAddr( 4, 0, 4 );                  // r4 <- first TIB entry == -> class object      asm.emitLAddr( 4, VM_Entrypoints.classForTypeField.getOffset(), 4 ); // r4 <- java Class for this VM_Class      asm.emitSTAddrU ( 4, BYTES_IN_ADDRESS, KLUDGE_TI_REG);                 // append class ptr to end of JNIRefs array      asm.emitSUBFC( 4, PROCESSOR_REGISTER, KLUDGE_TI_REG);  // pass offset in bytes    } else {      asm.emitSTAddrU ( 3, BYTES_IN_ADDRESS, KLUDGE_TI_REG);                 // append this ptr to end of JNIRefs array      asm.emitSUBFC( 4, PROCESSOR_REGISTER, KLUDGE_TI_REG);  // pass offset in bytes    }        // store the new JNIRefs array TOP back into JNIEnv	    asm.emitSUBFC(KLUDGE_TI_REG, PROCESSOR_REGISTER, KLUDGE_TI_REG);     // compute offset for the current TOP    asm.emitSTW(KLUDGE_TI_REG, VM_Entrypoints.JNIRefsTopField.getOffset(), S0);  }