Program: 149946
Project: 149946
Buggy source:
/** 
 * This method creates the stub to link native method.  It will be called from the lazy linker the first time a native method is invoked.  The stub generated will be patched by the lazy linker to link to the native method for all future calls. <p> <pre> The stub performs the following tasks in the prologue: -Allocate the glue frame -Save the PR register in the JNI Environment for reentering Java later -Shuffle the parameters in the registers to conform to the AIX convention -Save the nonvolatile registers in a known space in the frame to be used  for the GC stack map -Push a new JREF frame on the JNIRefs stack -Supply the first JNI argument:  the JNI environment pointer -Supply the second JNI argument:  class object if static, "this" if virtual -Setup the TOC (AIX only) and IP to the corresponding native code The stub performs the following tasks in the epilogue: -PR register is AIX nonvolatile, so it should be restored already -Restore the nonvolatile registers if GC has occurred -Pop the JREF frame off the JNIRefs stack -Check for pending exception and deliver to Java caller if present -Process the return value from native:  push onto caller's Java stack   The stack frame created by this stub conforms to the AIX convention: -6-word frame header -parameter save/spill area -one word flag to indicate whether GC has occurred during the native execution -16-word save area for nonvolatile registers | fp       | <- native frame | cr       | | lr       | | resv     | | resv     | + toc      + |          | |          | |----------|   | fp       | <- Java to C glue frame | cr/mid   | | lr       | | resv     | | resv     | + toc      + |   0      | spill area (at least 8 words reserved) |   1      | (also used for saving volatile regs during calls in prolog) |   2      | |   3      | |   4      | |   5      | |   6      | |   7      | |  ...     |  |          | |GC flag   | offset = JNI_SAVE_AREA_OFFSET           <- JNI_GC_FLAG_OFFSET |vol fpr1  | saved AIX volatile fpr during becomeNativeThread | ...      |  |vol fpr6  | saved AIX volatile fpr during becomeNativeThread |vol r4    | saved AIX volatile regs during Yield (to be removed when code moved to Java)    | ...      |  |vol r10   | saved AIX volatile regs during Yield    <- JNI_OS_PARAMETER_REGISTER_OFFSET |ENV       | VM_JNIEnvironment                       <- JNI_ENV_OFFSET |nonvol 17 | save 15 nonvolatile GPRs for GC stack mapper | ...      | |nonvol 31 |                                         <- JNI_RVM_NONVOLATILE_OFFSET |----------|    |  fp      | <- Java caller frame | mid      | | xxx      | |          | |          | |          | |----------| |          | </pre> Linux (and OSX) uses different transition scheme: the Java-to-Native transition stackframe consists of two mini frames: frame 1 has RVM's stack header with compiled method ID, and frame 2 has C (SVR4)'s stackframe layout.  Comparing to AIX transition frame, Linux version inserts a RVM frame header right above JNI_SAVE_AREA. <p> <pre> |            | <- Native callee frame   (lower addresses) | ......     | |------------| | fp         | <- Java to C glue frame (2) | lr         | | 0          | <- spill area, see VM_Compiler.getFrameSize | 1          | | .......    | |------------|  | fp         | <- Java to C glue frame (1) | lr         | | cmid       |  | padding    | | GC flag    | | Affinity   | | .......    | |------------|  | fp         | <- Java caller frame | lr         | | cmid       |                        (higher addresses) | .......    | </pre> VM_Runtime.unwindNativeStackFrame will return a pointer to glue frame (2). The lr slot of frame (2) holds the address of out-of-line machine code  which should be in bootimage, and GC shouldn't move this code.  The VM_JNIGCIterator returns the lr of frame (2) as the result of  getReturnAddressAddress.
 */
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();
  if (VM.VerifyAssertions)   VM._assert(T3 <= LAST_VOLATILE_GPR);
  if (VM.VerifyAssertions)   VM._assert(F3 <= LAST_VOLATILE_FPR);
  if (VM.VerifyAssertions)   VM._assert(S0 < S1 && S1 <= LAST_SCRATCH_GPR);
  Address nativeIP=method.getNativeIP();
  Address nativeTOC=method.getNativeTOC();
  asm.emitNativeStackOverflowCheck(frameSize + 14);
  int parameterAreaSize=method.getParameterWords() << LOG_BYTES_IN_STACKSLOT;
  asm.emitMFLR(REGISTER_ZERO);
  asm.emitSTAddr(REGISTER_ZERO,STACKFRAME_NEXT_INSTRUCTION_OFFSET,FP);
  if (VM.BuildForSVR4ABI || VM.BuildForMachOABI) {
    asm.emitSTAddrU(FP,-JNI_SAVE_AREA_SIZE,FP);
    asm.emitLVAL(S0,compiledMethodId);
    asm.emitSTW(S0,STACKFRAME_METHOD_ID_OFFSET,FP);
    asm.emitSTAddrU(FP,-frameSize + JNI_SAVE_AREA_SIZE,FP);
  }
 else {
    if (VM.VerifyAssertions)     VM._assert(VM.BuildForPowerOpenABI);
    asm.emitSTAddrU(FP,-frameSize,FP);
    asm.emitLVAL(S0,compiledMethodId);
    asm.emitSTW(S0,STACKFRAME_METHOD_ID_OFFSET,FP);
  }
  asm.emitLAddrOffset(S1,PROCESSOR_REGISTER,VM_Entrypoints.activeThreadField.getOffset());
  asm.emitLAddrOffset(S0,S1,VM_Entrypoints.jniEnvField.getOffset());
  asm.emitSTAddrOffset(PROCESSOR_REGISTER,S0,VM_Entrypoints.JNIEnvSavedPRField.getOffset());
  asm.emitSTAddr(S0,frameSize - JNI_ENV_OFFSET,FP);
  if (VM.BuildForSVR4ABI || VM.BuildForMachOABI) {
    asm.emitLAddr(PROCESSOR_REGISTER,0,FP);
    asm.emitSTAddrOffset(PROCESSOR_REGISTER,S0,VM_Entrypoints.JNITopJavaFPField.getOffset());
  }
 else {
    if (VM.VerifyAssertions)     VM._assert(VM.BuildForPowerOpenABI);
    asm.emitSTAddrOffset(FP,S0,VM_Entrypoints.JNITopJavaFPField.getOffset());
  }
  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);
  }
  asm.emitLVAL(PROCESSOR_REGISTER,0);
  asm.emitSTW(PROCESSOR_REGISTER,frameSize - JNI_GC_FLAG_OFFSET,FP);
  storeParameters(asm,frameSize,method,klass);
  asm.emitLAddrOffset(S1,JTOC,VM_Entrypoints.invokeNativeFunctionInstructionsField.getOffset());
  asm.emitMTCTR(S1);
  asm.emitLVALAddr(JTOC,nativeTOC);
  asm.emitLVALAddr(S1,nativeIP);
  asm.emitBCCTRL();
  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.emitLAddrOffset(S0,PROCESSOR_REGISTER,VM_Entrypoints.activeThreadField.getOffset());
  asm.emitLAddrOffset(S0,S0,VM_Entrypoints.jniEnvField.getOffset());
  asm.emitLAddrOffset(S1,S0,VM_Entrypoints.JNIRefsField.getOffset());
  asm.emitLIntOffset(T2,S0,VM_Entrypoints.JNIRefsSavedFPField.getOffset());
  asm.emitADDI(T3,-BYTES_IN_STACKSLOT,T2);
  asm.emitSTWoffset(T3,S0,VM_Entrypoints.JNIRefsTopField.getOffset());
  asm.emitLIntX(T2,S1,T2);
  asm.emitSTWoffset(T2,S0,VM_Entrypoints.JNIRefsSavedFPField.getOffset());
  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);
  }
  VM_TypeReference returnType=method.getReturnType();
  if (returnType.isReferenceType()) {
    asm.emitLAddrX(T0,S1,T0);
  }
  asm.emitADDI(FP,+frameSize,FP);
  asm.emitLAddr(REGISTER_ZERO,STACKFRAME_NEXT_INSTRUCTION_OFFSET,FP);
  asm.emitMTLR(REGISTER_ZERO);
  asm.emitLAddrOffset(T2,S0,VM_Entrypoints.JNIPendingExceptionField.getOffset());
  asm.emitLVAL(T3,0);
  asm.emitSTAddrOffset(T3,S0,VM_Entrypoints.JNIPendingExceptionField.getOffset());
  asm.emitCMPAddr(T2,T3);
  VM_ForwardReference fr3=asm.emitForwardBC(NE);
  asm.emitBCLR();
  fr3.resolve(asm);
  asm.emitLAddrToc(T3,VM_Entrypoints.athrowMethod.getOffset());
  asm.emitMTCTR(T3);
  asm.emitMR(T0,T2);
  asm.emitBCCTR();
  VM_MachineCode machineCode=asm.makeMachineCode();
  cm.compileComplete((VM_CodeArray)machineCode.getInstructions());
  return cm;
}

Fixed version (ground truth):
/** 
 * This method creates the stub to link native method.  It will be called from the lazy linker the first time a native method is invoked.  The stub generated will be patched by the lazy linker to link to the native method for all future calls. <p> <pre> The stub performs the following tasks in the prologue: -Allocate the glue frame -Save the PR register in the JNI Environment for reentering Java later -Shuffle the parameters in the registers to conform to the AIX convention -Save the nonvolatile registers in a known space in the frame to be used  for the GC stack map -Push a new JREF frame on the JNIRefs stack -Supply the first JNI argument:  the JNI environment pointer -Supply the second JNI argument:  class object if static, "this" if virtual -Setup the TOC (AIX only) and IP to the corresponding native code The stub performs the following tasks in the epilogue: -PR register is AIX nonvolatile, so it should be restored already -Restore the nonvolatile registers if GC has occurred -Pop the JREF frame off the JNIRefs stack -Check for pending exception and deliver to Java caller if present -Process the return value from native:  push onto caller's Java stack   The stack frame created by this stub conforms to the AIX convention: -6-word frame header -parameter save/spill area -one word flag to indicate whether GC has occurred during the native execution -16-word save area for nonvolatile registers | fp       | <- native frame | cr       | | lr       | | resv     | | resv     | + toc      + |          | |          | |----------|   | fp       | <- Java to C glue frame | cr/mid   | | lr       | | resv     | | resv     | + toc      + |   0      | spill area (at least 8 words reserved) |   1      | (also used for saving volatile regs during calls in prolog) |   2      | |   3      | |   4      | |   5      | |   6      | |   7      | |  ...     |  |          | |GC flag   | offset = JNI_SAVE_AREA_OFFSET           <- JNI_GC_FLAG_OFFSET |vol fpr1  | saved AIX volatile fpr during becomeNativeThread | ...      |  |vol fpr6  | saved AIX volatile fpr during becomeNativeThread |vol r4    | saved AIX volatile regs during Yield (to be removed when code moved to Java)    | ...      |  |vol r10   | saved AIX volatile regs during Yield    <- JNI_OS_PARAMETER_REGISTER_OFFSET |ENV       | VM_JNIEnvironment                       <- JNI_ENV_OFFSET |nonvol 17 | save 15 nonvolatile GPRs for GC stack mapper | ...      | |nonvol 31 |                                         <- JNI_RVM_NONVOLATILE_OFFSET |----------|    |  fp      | <- Java caller frame | mid      | | xxx      | |          | |          | |          | |----------| |          | </pre> Linux (and OSX) uses different transition scheme: the Java-to-Native transition stackframe consists of two mini frames: frame 1 has RVM's stack header with compiled method ID, and frame 2 has C (SVR4)'s stackframe layout.  Comparing to AIX transition frame, Linux version inserts a RVM frame header right above JNI_SAVE_AREA. <p> <pre> |            | <- Native callee frame   (lower addresses) | ......     | |------------| | fp         | <- Java to C glue frame (2) | lr         | | 0          | <- spill area, see VM_Compiler.getFrameSize | 1          | | .......    | |------------|  | fp         | <- Java to C glue frame (1) | lr         | | cmid       |  | padding    | | GC flag    | | Affinity   | | .......    | |------------|  | fp         | <- Java caller frame | lr         | | cmid       |                        (higher addresses) | .......    | </pre> VM_Runtime.unwindNativeStackFrame will return a pointer to glue frame (2). The lr slot of frame (2) holds the address of out-of-line machine code  which should be in bootimage, and GC shouldn't move this code.  The VM_JNIGCIterator returns the lr of frame (2) as the result of  getReturnAddressAddress.
 */
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();
  if (VM.VerifyAssertions)   VM._assert(T3 <= LAST_VOLATILE_GPR);
  if (VM.VerifyAssertions)   VM._assert(F3 <= LAST_VOLATILE_FPR);
  if (VM.VerifyAssertions)   VM._assert(S0 < S1 && S1 <= LAST_SCRATCH_GPR);
  Address nativeIP=method.getNativeIP();
  Address nativeTOC=method.getNativeTOC();
  asm.emitNativeStackOverflowCheck(frameSize + 14);
  int parameterAreaSize=method.getParameterWords() << LOG_BYTES_IN_STACKSLOT;
  asm.emitMFLR(REGISTER_ZERO);
  asm.emitSTAddr(REGISTER_ZERO,STACKFRAME_NEXT_INSTRUCTION_OFFSET,FP);
  if (VM.BuildForSVR4ABI || VM.BuildForMachOABI) {
    asm.emitSTAddrU(FP,-JNI_SAVE_AREA_SIZE,FP);
    asm.emitLVAL(S0,compiledMethodId);
    asm.emitSTW(S0,STACKFRAME_METHOD_ID_OFFSET,FP);
    asm.emitSTAddrU(FP,-frameSize + JNI_SAVE_AREA_SIZE,FP);
    asm.emitLVAL(S0,INVISIBLE_METHOD_ID);
    asm.emitSTW(S0,STACKFRAME_METHOD_ID_OFFSET,FP);
  }
 else {
    if (VM.VerifyAssertions)     VM._assert(VM.BuildForPowerOpenABI);
    asm.emitSTAddrU(FP,-frameSize,FP);
    asm.emitLVAL(S0,compiledMethodId);
    asm.emitSTW(S0,STACKFRAME_METHOD_ID_OFFSET,FP);
  }
  asm.emitLAddrOffset(S1,PROCESSOR_REGISTER,VM_Entrypoints.activeThreadField.getOffset());
  asm.emitLAddrOffset(S0,S1,VM_Entrypoints.jniEnvField.getOffset());
  asm.emitSTAddrOffset(PROCESSOR_REGISTER,S0,VM_Entrypoints.JNIEnvSavedPRField.getOffset());
  asm.emitSTAddr(S0,frameSize - JNI_ENV_OFFSET,FP);
  if (VM.BuildForSVR4ABI || VM.BuildForMachOABI) {
    asm.emitLAddr(PROCESSOR_REGISTER,0,FP);
    asm.emitSTAddrOffset(PROCESSOR_REGISTER,S0,VM_Entrypoints.JNITopJavaFPField.getOffset());
  }
 else {
    if (VM.VerifyAssertions)     VM._assert(VM.BuildForPowerOpenABI);
    asm.emitSTAddrOffset(FP,S0,VM_Entrypoints.JNITopJavaFPField.getOffset());
  }
  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);
  }
  asm.emitLVAL(PROCESSOR_REGISTER,0);
  asm.emitSTW(PROCESSOR_REGISTER,frameSize - JNI_GC_FLAG_OFFSET,FP);
  storeParameters(asm,frameSize,method,klass);
  asm.emitLAddrOffset(S1,JTOC,VM_Entrypoints.invokeNativeFunctionInstructionsField.getOffset());
  asm.emitMTCTR(S1);
  asm.emitLVALAddr(JTOC,nativeTOC);
  asm.emitLVALAddr(S1,nativeIP);
  asm.emitBCCTRL();
  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.emitLAddrOffset(S0,PROCESSOR_REGISTER,VM_Entrypoints.activeThreadField.getOffset());
  asm.emitLAddrOffset(S0,S0,VM_Entrypoints.jniEnvField.getOffset());
  asm.emitLAddrOffset(S1,S0,VM_Entrypoints.JNIRefsField.getOffset());
  asm.emitLIntOffset(T2,S0,VM_Entrypoints.JNIRefsSavedFPField.getOffset());
  asm.emitADDI(T3,-BYTES_IN_STACKSLOT,T2);
  asm.emitSTWoffset(T3,S0,VM_Entrypoints.JNIRefsTopField.getOffset());
  asm.emitLIntX(T2,S1,T2);
  asm.emitSTWoffset(T2,S0,VM_Entrypoints.JNIRefsSavedFPField.getOffset());
  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);
  }
  VM_TypeReference returnType=method.getReturnType();
  if (returnType.isReferenceType()) {
    asm.emitLAddrX(T0,S1,T0);
  }
  asm.emitADDI(FP,+frameSize,FP);
  asm.emitLAddr(REGISTER_ZERO,STACKFRAME_NEXT_INSTRUCTION_OFFSET,FP);
  asm.emitMTLR(REGISTER_ZERO);
  asm.emitLAddrOffset(T2,S0,VM_Entrypoints.JNIPendingExceptionField.getOffset());
  asm.emitLVAL(T3,0);
  asm.emitSTAddrOffset(T3,S0,VM_Entrypoints.JNIPendingExceptionField.getOffset());
  asm.emitCMPAddr(T2,T3);
  VM_ForwardReference fr3=asm.emitForwardBC(NE);
  asm.emitBCLR();
  fr3.resolve(asm);
  asm.emitLAddrToc(T3,VM_Entrypoints.athrowMethod.getOffset());
  asm.emitMTCTR(T3);
  asm.emitMR(T0,T2);
  asm.emitBCCTR();
  VM_MachineCode machineCode=asm.makeMachineCode();
  cm.compileComplete((VM_CodeArray)machineCode.getInstructions());
  return cm;
}