asmArg.emitSTAddrU(nextVMArgReg++, BYTES_IN_ADDRESS, KLUDGE_TI_REG); asmArg.emitSUBFC(nextOSArgReg++, PROCESSOR_REGISTER, KLUDGE_TI_REG);
asmArg.emitCMPI(nextVMArgReg, 0); VM_ForwardReference isNull = asmArg.emitForwardBC(EQ);  asmArg.emitSTAddrU(nextVMArgReg, BYTES_IN_ADDRESS, KLUDGE_TI_REG); asmArg.emitSUBFC(nextOSArgReg, PROCESSOR_REGISTER, KLUDGE_TI_REG); VM_ForwardReference done = asmArg.emitForwardB();  isNull.resolve(asmArg); asmArg.emitMR(nextOSArgReg, nextVMArgReg);  done.resolve(asmArg); nextVMArgReg++; nextOSArgReg++;
  private static void generateParameterPassingCode(VM_Assembler asm,                                                   VM_TypeReference[] types,                                                   int nextVMArgReg,                                                   int nextVMArgFloatReg,                                                   int spillOffsetVM,                                                   int nextOSArgReg,                                                   int nextOSArgFloatReg,                                                   int spillOffsetOS) {    // 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    int numArguments = types.length;    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 (nextOSArgReg<=LAST_OS_PARAMETER_GPR) {          nextOSArgReg++;          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;        }                spillOffsetOS+=BYTES_IN_STACKSLOT;        // 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, spillOffsetOS - BYTES_IN_FLOAT, FP);           }          nextOSArgFloatReg++;          nextVMArgFloatReg++;          } else if (nextVMArgFloatReg<=LAST_VOLATILE_FPR) {          // (2b) run out of FPR in OS, but still have 2 more FPR in VM,          // so FPR[14:15] goes to the callee spill area          asmArg.emitSTFS(nextVMArgFloatReg, spillOffsetOS - BYTES_IN_FLOAT, FP);          nextVMArgFloatReg++;        } 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          //Kris Venstermans: Attention, different calling convention !!          spillOffsetVM+=BYTES_IN_STACKSLOT;          asmArg.emitLFS(FIRST_SCRATCH_FPR, spillOffsetVM - BYTES_IN_FLOAT, FP);          asmArg.emitSTFS(FIRST_SCRATCH_FPR, spillOffsetOS - BYTES_IN_FLOAT, FP);        }      } 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 (nextOSArgReg<=LAST_OS_PARAMETER_GPR) {            nextOSArgReg++;            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 (nextOSArgReg<=LAST_OS_PARAMETER_GPR-1) {            nextOSArgReg+=2;            mustSaveFloatToSpill = false;          } else {            // if only one GPR is left, reserve it anyway although it won't be used            if (nextOSArgReg<=LAST_OS_PARAMETER_GPR)              nextOSArgReg++;            mustSaveFloatToSpill = true;          }        }        spillOffsetOS+=BYTES_IN_DOUBLE; //Kris Venstermans: equals 2 slots on 32-bit platforms and 1 slot on 64-bit platform        // 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, spillOffsetOS - BYTES_IN_DOUBLE, FP);           }          nextOSArgFloatReg++;          nextVMArgFloatReg++;          } else if (nextVMArgFloatReg<=LAST_VOLATILE_FPR) {          // (2b) run out of FPR in OS, but still have 2 more FPR in VM,          // so FPR[14:15] goes to the callee spill area          asmArg.emitSTFD(nextVMArgFloatReg, spillOffsetOS - BYTES_IN_DOUBLE, FP);          nextVMArgFloatReg++;        } 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_DOUBLE;          asmArg.emitLFD(FIRST_SCRATCH_FPR, spillOffsetVM - BYTES_IN_DOUBLE, FP);          asmArg.emitSTFD(FIRST_SCRATCH_FPR, spillOffsetOS - BYTES_IN_DOUBLE, FP);        }      } else if (VM.BuildFor32Addr && types[arg].isLongType()) {        // For 64-bit int arguments on 32-bit platforms        //        spillOffsetOS+=BYTES_IN_LONG;        // (1a) fit in OS register, move the pair        if (nextOSArgReg<=LAST_OS_PARAMETER_GPR-1) {          asmArg.emitMR(nextOSArgReg+1, nextVMArgReg+1);  // move lo-word first          asmArg.emitMR(nextOSArgReg, nextVMArgReg);      // so it doesn't overwritten          nextOSArgReg+=2;          nextVMArgReg+=2;        } else if (nextOSArgReg==LAST_OS_PARAMETER_GPR &&          nextVMArgReg<=LAST_VOLATILE_GPR-1) {          // (1b) fit in VM register but straddle across OS register/spill          asmArg.emitSTW(nextVMArgReg+1, spillOffsetOS - BYTES_IN_STACKSLOT, FP);   // move lo-word first, so it doesn't overwritten          asmArg.emitMR(nextOSArgReg, nextVMArgReg);          nextOSArgReg+=2;          nextVMArgReg+=2;                } else if (nextOSArgReg>LAST_OS_PARAMETER_GPR &&                   nextVMArgReg<=LAST_VOLATILE_GPR-1) {          // (1c) fit in VM register, spill in OS without straddling register/spill          asmArg.emitSTW(nextVMArgReg++, spillOffsetOS - 2*BYTES_IN_STACKSLOT, FP);          asmArg.emitSTW(nextVMArgReg++, spillOffsetOS - BYTES_IN_STACKSLOT, FP);        } else if (nextVMArgReg==LAST_VOLATILE_GPR) {          // (1d) split across VM/spill, spill in OS          spillOffsetVM+=BYTES_IN_STACKSLOT;          asmArg.emitSTW(nextVMArgReg++, spillOffsetOS - 2*BYTES_IN_STACKSLOT, FP);          asmArg.emitLWZ(REGISTER_ZERO, spillOffsetVM - BYTES_IN_STACKSLOT, FP);          asmArg.emitSTW(REGISTER_ZERO, spillOffsetOS - BYTES_IN_STACKSLOT, FP);        } else {          // (1e) spill both in VM and OS          spillOffsetVM+=BYTES_IN_LONG;          asmArg.emitLFD(FIRST_SCRATCH_FPR, spillOffsetVM - BYTES_IN_LONG, FP);          asmArg.emitSTFD(FIRST_SCRATCH_FPR, spillOffsetOS - BYTES_IN_LONG, FP);        }      } else if (VM.BuildFor64Addr && types[arg].isLongType()) {        // For 64-bit int arguments on 64-bit platforms        //        spillOffsetOS+=BYTES_IN_LONG;        // (1a) fit in OS register, move the register        if (nextOSArgReg<=LAST_OS_PARAMETER_GPR) {          asmArg.emitMR(nextOSArgReg++, nextVMArgReg++);        // (1b) spill OS register, but still fit in VM register        } else if (nextVMArgReg<=LAST_VOLATILE_GPR) {          asmArg.emitSTAddr(nextVMArgReg++, spillOffsetOS - BYTES_IN_LONG, FP);        } else {          // (1c) spill VM register          spillOffsetVM+=BYTES_IN_LONG;          asmArg.emitLAddr(REGISTER_ZERO,spillOffsetVM - BYTES_IN_LONG, FP);        // retrieve arg from VM spill area          asmArg.emitSTAddr(REGISTER_ZERO, spillOffsetOS - BYTES_IN_LONG, FP);        }      } else if (types[arg].isReferenceType() ) {               // For reference type, replace with handlers before passing to OS        //        spillOffsetOS+=BYTES_IN_ADDRESS;                // (1a) fit in OS register, move the register        if (nextOSArgReg<=LAST_OS_PARAMETER_GPR) {          asmArg.emitSTAddrU(nextVMArgReg++, BYTES_IN_ADDRESS, KLUDGE_TI_REG);          // append ref to end of JNIRefs array          asmArg.emitSUBFC(nextOSArgReg++, PROCESSOR_REGISTER, KLUDGE_TI_REG);  // pass offset in bytes of jref        } else if (nextVMArgReg<=LAST_VOLATILE_GPR) {          // (1b) spill OS 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, spillOffsetOS - BYTES_IN_ADDRESS, FP);       // spill into OS frame        } else {          // (1c) spill VM register          spillOffsetVM+=BYTES_IN_STACKSLOT;          asmArg.emitLAddr(REGISTER_ZERO, spillOffsetVM - BYTES_IN_ADDRESS , 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, spillOffsetOS - BYTES_IN_ADDRESS, FP);       // spill into OS frame        }      } else {         // For all other types: int, short, char, byte, boolean         spillOffsetOS+=BYTES_IN_STACKSLOT;        // (1a) fit in OS register, move the register        if (nextOSArgReg<=LAST_OS_PARAMETER_GPR) {          asmArg.emitMR(nextOSArgReg++, nextVMArgReg++);        }        // (1b) spill OS register, but still fit in VM register        else if (nextVMArgReg<=LAST_VOLATILE_GPR) {          asmArg.emitSTAddr(nextVMArgReg++, spillOffsetOS - BYTES_IN_ADDRESS, FP);        } else {          // (1c) spill VM register          spillOffsetVM+=BYTES_IN_STACKSLOT;          asmArg.emitLInt(REGISTER_ZERO,spillOffsetVM - BYTES_IN_INT, FP);        // retrieve arg from VM spill area          asmArg.emitSTAddr(REGISTER_ZERO, spillOffsetOS - BYTES_IN_ADDRESS, FP);        }      }    }        // 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());    }  }