Program: 150227
Project: 150227
Buggy source:
/** 
 * This method supports var args passed from C In the AIX C convention, the caller keeps the first 8 words in registers and  the rest in the spill area in the caller frame.  The callee will push the values in registers out to the spill area of the caller frame and use the beginning  address of this spill area as the var arg address For the JNI functions that takes var args, their prolog code will save the var arg in the glue frame because the values in the register may be lost by  subsequent calls. This method copies the var arg values that were saved earlier in glue frame into the spill area of the original caller, thereby doing the work that the callee normally performs in the AIX C convention. NOTE:  this method assumes that it is immediately above the  invokeWithDotDotVarArg frame, the JNI frame, the glue frame and  the C caller frame in the respective order.   Therefore, this method will not work if called from anywhere else |  fp  | <- VM_JNIEnvironment.pushVarArgToSpillArea | mid  | | xxx  | |      | |      | |------|    |  fp  | <- VM_JNIEnvironment.invokeWithDotDotVarArg frame | mid  | | xxx  | |      | |      | |      | |------|    |  fp  | <- JNI method frame | mid  | | xxx  | |      | |      | |      | |------| |  fp  | <- glue frame | mid  | + xxx  + | r3   |   volatile save area | r4   | | r5   | | r6   |   vararg GPR[6-10]save area   <- VARARG_AREA_OFFSET | r7   | | r8   | | r9   | | r10  | | fpr1 |   vararg FPR[1-3] save area (also used as volatile FPR[1-6] save area) | fpr2 | | fpr3 | | fpr4 | | fpr5 | + fpr6 + | r13  |   nonvolatile GPR[13-31] save area | ...  | + r31  + | fpr14|   nonvolatile FPR[14-31] save area | ...  | | fpr31| |topjav|   offset to preceding Java to C glue frame |------|   | fp   | <- Native C caller frame | cr   | | lr   | | resv | | resv | + toc  + |   0  |    spill area initially not filled |   1  |    to be filled by this method |   2  | |   3  | |   4  | |   5  | |   6  | |   7  | |   8  |    spill area already filled by caller |   9  | |      | |      | |      |
 * @param methodID a VM_MemberReference id
 * @param skip4Args if true, the calling JNI function has 4 args before the varargif false, the calling JNI function has 3 args before the vararg
 * @return the starting address of the vararg in the caller stack frame
 */
private static VM_Address pushVarArgToSpillArea(int methodID,boolean skip4Args) throws Exception {
  int glueFrameSize=JNI_GLUE_FRAME_SIZE;
  VM_Address gluefp=VM_Magic.getMemoryAddress(VM_Magic.getFramePointer().add(VM_Constants.STACKFRAME_FRAME_POINTER_OFFSET));
  gluefp=VM_Magic.getMemoryAddress(gluefp.add(VM_Constants.STACKFRAME_FRAME_POINTER_OFFSET));
  gluefp=VM_Magic.getMemoryAddress(gluefp.add(VM_Constants.STACKFRAME_FRAME_POINTER_OFFSET));
  int varargGPROffset=VARARG_AREA_OFFSET + (skip4Args ? BYTES_IN_ADDRESS : 0);
  int varargFPROffset=varargGPROffset + 5 * BYTES_IN_ADDRESS;
  int spillAreaLimit=glueFrameSize + NATIVE_FRAME_HEADER_SIZE + 8 * BYTES_IN_ADDRESS;
  int spillAreaOffset=glueFrameSize + NATIVE_FRAME_HEADER_SIZE + (skip4Args ? 4 * BYTES_IN_ADDRESS : 3 * BYTES_IN_ADDRESS);
  VM_Address varargAddress=gluefp.add(spillAreaOffset);
  VM_Method targetMethod=VM_MemberReference.getMemberRef(methodID).asMethodReference().resolve();
  VM_TypeReference[] argTypes=targetMethod.getParameterTypes();
  int argCount=argTypes.length;
  for (int i=0; i < argCount && spillAreaOffset < spillAreaLimit; i++) {
    VM_Word hiword, loword;
    if (argTypes[i].isFloatType() || argTypes[i].isDoubleType()) {
      hiword=VM_Magic.getMemoryWord(gluefp.add(varargFPROffset));
      varargFPROffset+=BYTES_IN_ADDRESS;
      if (VM.BuildFor32Addr) {
        loword=VM_Magic.getMemoryWord(gluefp.add(varargFPROffset));
        varargFPROffset+=BYTES_IN_ADDRESS;
      }
      VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),hiword);
      spillAreaOffset+=BYTES_IN_ADDRESS;
      if (VM.BuildFor32Addr) {
        VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),loword);
        spillAreaOffset+=BYTES_IN_ADDRESS;
      }
    }
 else     if (argTypes[i].isLongType()) {
      hiword=VM_Magic.getMemoryWord(gluefp.add(varargGPROffset));
      varargGPROffset+=BYTES_IN_ADDRESS;
      VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),hiword);
      spillAreaOffset+=BYTES_IN_ADDRESS;
      if (VM.BuildFor32Addr && spillAreaOffset < spillAreaLimit) {
        loword=VM_Magic.getMemoryWord(gluefp.add(varargGPROffset));
        varargGPROffset+=BYTES_IN_ADDRESS;
        VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),loword);
        spillAreaOffset+=BYTES_IN_ADDRESS;
      }
    }
 else {
      hiword=VM_Magic.getMemoryWord(gluefp.add(varargGPROffset));
      varargGPROffset+=BYTES_IN_ADDRESS;
      VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),hiword);
      spillAreaOffset+=BYTES_IN_ADDRESS;
    }
  }
  return varargAddress;
}

Fixed version (ground truth):
/** 
 * This method supports var args passed from C In the AIX C convention, the caller keeps the first 8 words in registers and  the rest in the spill area in the caller frame.  The callee will push the values in registers out to the spill area of the caller frame and use the beginning  address of this spill area as the var arg address For the JNI functions that takes var args, their prolog code will save the var arg in the glue frame because the values in the register may be lost by  subsequent calls. This method copies the var arg values that were saved earlier in glue frame into the spill area of the original caller, thereby doing the work that the callee normally performs in the AIX C convention. NOTE:  this method assumes that it is immediately above the  invokeWithDotDotVarArg frame, the JNI frame, the glue frame and  the C caller frame in the respective order.   Therefore, this method will not work if called from anywhere else |  fp  | <- VM_JNIEnvironment.pushVarArgToSpillArea | mid  | | xxx  | |      | |      | |------|    |  fp  | <- VM_JNIEnvironment.invokeWithDotDotVarArg frame | mid  | | xxx  | |      | |      | |      | |------|    |  fp  | <- JNI method frame | mid  | | xxx  | |      | |      | |      | |------| |  fp  | <- glue frame | mid  | + xxx  + | r3   |   volatile save area | r4   | | r5   | | r6   |   vararg GPR[6-10]save area   <- VARARG_AREA_OFFSET | r7   | | r8   | | r9   | | r10  | | fpr1 |   vararg FPR[1-3] save area (also used as volatile FPR[1-6] save area) | fpr2 | | fpr3 | | fpr4 | | fpr5 | + fpr6 + | r13  |   nonvolatile GPR[13-31] save area | ...  | + r31  + | fpr14|   nonvolatile FPR[14-31] save area | ...  | | fpr31| |topjav|   offset to preceding Java to C glue frame |------|   | fp   | <- Native C caller frame | cr   | | lr   | | resv | | resv | + toc  + |   0  |    spill area initially not filled |   1  |    to be filled by this method |   2  | |   3  | |   4  | |   5  | |   6  | |   7  | |   8  |    spill area already filled by caller |   9  | |      | |      | |      |
 * @param methodID a VM_MemberReference id
 * @param skip4Args if true, the calling JNI function has 4 args before the varargif false, the calling JNI function has 3 args before the vararg
 * @return the starting address of the vararg in the caller stack frame
 */
private static VM_Address pushVarArgToSpillArea(int methodID,boolean skip4Args) throws Exception, VM_PragmaNoInline {
  int glueFrameSize=JNI_GLUE_FRAME_SIZE;
  VM_Address gluefp=VM_Magic.getMemoryAddress(VM_Magic.getFramePointer().add(VM_Constants.STACKFRAME_FRAME_POINTER_OFFSET));
  gluefp=VM_Magic.getMemoryAddress(gluefp.add(VM_Constants.STACKFRAME_FRAME_POINTER_OFFSET));
  gluefp=VM_Magic.getMemoryAddress(gluefp.add(VM_Constants.STACKFRAME_FRAME_POINTER_OFFSET));
  int varargGPROffset=VARARG_AREA_OFFSET + (skip4Args ? BYTES_IN_ADDRESS : 0);
  int varargFPROffset=varargGPROffset + 5 * BYTES_IN_ADDRESS;
  int spillAreaLimit=glueFrameSize + NATIVE_FRAME_HEADER_SIZE + 8 * BYTES_IN_ADDRESS;
  int spillAreaOffset=glueFrameSize + NATIVE_FRAME_HEADER_SIZE + (skip4Args ? 4 * BYTES_IN_ADDRESS : 3 * BYTES_IN_ADDRESS);
  VM_Address varargAddress=gluefp.add(spillAreaOffset);
  VM_Method targetMethod=VM_MemberReference.getMemberRef(methodID).asMethodReference().resolve();
  VM_TypeReference[] argTypes=targetMethod.getParameterTypes();
  int argCount=argTypes.length;
  for (int i=0; i < argCount && spillAreaOffset < spillAreaLimit; i++) {
    VM_Word hiword, loword;
    if (argTypes[i].isFloatType() || argTypes[i].isDoubleType()) {
      hiword=VM_Magic.getMemoryWord(gluefp.add(varargFPROffset));
      varargFPROffset+=BYTES_IN_ADDRESS;
      if (VM.BuildFor32Addr) {
        loword=VM_Magic.getMemoryWord(gluefp.add(varargFPROffset));
        varargFPROffset+=BYTES_IN_ADDRESS;
      }
      VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),hiword);
      spillAreaOffset+=BYTES_IN_ADDRESS;
      if (VM.BuildFor32Addr) {
        VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),loword);
        spillAreaOffset+=BYTES_IN_ADDRESS;
      }
    }
 else     if (argTypes[i].isLongType()) {
      hiword=VM_Magic.getMemoryWord(gluefp.add(varargGPROffset));
      varargGPROffset+=BYTES_IN_ADDRESS;
      VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),hiword);
      spillAreaOffset+=BYTES_IN_ADDRESS;
      if (VM.BuildFor32Addr && spillAreaOffset < spillAreaLimit) {
        loword=VM_Magic.getMemoryWord(gluefp.add(varargGPROffset));
        varargGPROffset+=BYTES_IN_ADDRESS;
        VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),loword);
        spillAreaOffset+=BYTES_IN_ADDRESS;
      }
    }
 else {
      hiword=VM_Magic.getMemoryWord(gluefp.add(varargGPROffset));
      varargGPROffset+=BYTES_IN_ADDRESS;
      VM_Magic.setMemoryWord(gluefp.add(spillAreaOffset),hiword);
      spillAreaOffset+=BYTES_IN_ADDRESS;
    }
  }
  return varargAddress;
}