use of org.jikesrvm.ppc.RegisterConstants.GPR in project JikesRVM by JikesRVM.
the class JNICompiler method genSVR4ParameterPassingCode.
/**
* Generates instructions to copy parameters from RVM convention to OS convention.
* @param asm The {@link Assembler} object
* @param types The parameter types
* @param nextVMArgReg The first parameter GPR in RVM convention,
* the last parameter GPR is defined as LAST_VOLATILE_GPR.
* @param nextVMArgFloatReg The first parameter FPR in RVM convention,
* the last parameter FPR is defined as LAST_VOLATILE_FPR.
* @param spillOffsetVM The spill offset (related to FP) in RVM convention
* @param nextOSArgReg the first parameter GPR in OS convention,
* the last parameter GPR is defined as LAST_OS_PARAMETER_GPR.
* @param nextOSArgFloatReg The first parameter FPR in OS convention,
* the last parameter FPR is defined as LAST_OS_PARAMETER_FPR.
* @param spillOffsetOS The spill offset (related to FP) in OS convention
*/
private static void genSVR4ParameterPassingCode(Assembler asm, TypeReference[] types, int nextVMArgReg, int nextVMArgFloatReg, int spillOffsetVM, int nextOSArgReg, int nextOSArgFloatReg, int spillOffsetOS) {
if (VM.BuildForSVR4ABI) {
// create one 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 Assembler in the forward pass, then in the reverse pass, each Assembler
// emist the instruction sequence and copies it into the main Assembler
int numArguments = types.length;
Assembler[] asmForArgs = new Assembler[numArguments];
for (int arg = 0; arg < numArguments; arg++) {
asmForArgs[arg] = new Assembler(0);
Assembler asmArg = asmForArgs[arg];
//
if (types[arg].isFloatingPointType()) {
boolean is32bits = types[arg].isFloatType();
// 1. check the source, the value will be in srcVMArg
// scratch fpr
FPR srcVMArg;
if (nextVMArgFloatReg <= LAST_VOLATILE_FPR.value()) {
srcVMArg = FPR.lookup(nextVMArgFloatReg);
nextVMArgFloatReg++;
} else {
srcVMArg = FIRST_SCRATCH_FPR;
// VM float reg is in spill area
if (is32bits) {
spillOffsetVM += BYTES_IN_STACKSLOT;
asmArg.emitLFS(srcVMArg, spillOffsetVM - BYTES_IN_FLOAT, FP);
} else {
asmArg.emitLFD(srcVMArg, spillOffsetVM, FP);
spillOffsetVM += BYTES_IN_DOUBLE;
}
}
// 2. check the destination,
if (nextOSArgFloatReg <= LAST_OS_PARAMETER_FPR.value()) {
// leave it there
nextOSArgFloatReg++;
} else {
if (VM.BuildForSVR4ABI) {
if (is32bits) {
asmArg.emitSTFS(srcVMArg, spillOffsetOS, FP);
spillOffsetOS += BYTES_IN_ADDRESS;
} else {
// spill it, round the spill address to 8
// assuming FP is aligned to 8
spillOffsetOS = (spillOffsetOS + 7) & -8;
asmArg.emitSTFD(srcVMArg, spillOffsetOS, FP);
spillOffsetOS += BYTES_IN_DOUBLE;
}
}
}
// for 64-bit long arguments
} else if (types[arg].isLongType() && VM.BuildFor32Addr) {
// handle OS first
boolean dstSpilling;
// it is register number or spilling offset
int regOrSpilling = -1;
// 1. check if Linux register > 9
if (nextOSArgReg > (LAST_OS_PARAMETER_GPR.value() - 1)) {
// goes to spilling area
dstSpilling = true;
if (VM.BuildForSVR4ABI) {
/* NOTE: following adjustment is not stated in SVR4 ABI, but
* was implemented in GCC.
* -- Feng
*/
nextOSArgReg = LAST_OS_PARAMETER_GPR.value() + 1;
// do alignment and compute spilling offset
spillOffsetOS = (spillOffsetOS + 7) & -8;
regOrSpilling = spillOffsetOS;
spillOffsetOS += BYTES_IN_LONG;
}
} else {
// use registers
dstSpilling = false;
if (VM.BuildForSVR4ABI) {
// rounds to odd
// if gpr is even, gpr += 1
nextOSArgReg += (nextOSArgReg + 1) & 0x01;
regOrSpilling = nextOSArgReg;
nextOSArgReg += 2;
}
}
// handle RVM source
if (nextVMArgReg < LAST_VOLATILE_GPR.value()) {
// both parts in registers
if (dstSpilling) {
asmArg.emitSTW(GPR.lookup(nextVMArgReg + 1), regOrSpilling + 4, FP);
if (VM.BuildForSVR4ABI) {
asmArg.emitSTW(GPR.lookup(nextVMArgReg), regOrSpilling, FP);
}
} else {
asmArg.emitMR(GPR.lookup(regOrSpilling + 1), GPR.lookup(nextVMArgReg + 1));
asmArg.emitMR(GPR.lookup(regOrSpilling), GPR.lookup(nextVMArgReg));
}
// advance register counting, Linux register number
// already advanced
nextVMArgReg += 2;
} else if (nextVMArgReg == LAST_VOLATILE_GPR.value()) {
// VM striding
if (dstSpilling) {
asmArg.emitLWZ(REGISTER_ZERO, spillOffsetVM, FP);
asmArg.emitSTW(REGISTER_ZERO, regOrSpilling + 4, FP);
asmArg.emitSTW(GPR.lookup(nextVMArgReg), regOrSpilling, FP);
} else {
asmArg.emitLWZ(GPR.lookup(regOrSpilling + 1), spillOffsetVM, FP);
asmArg.emitMR(GPR.lookup(regOrSpilling), GPR.lookup(nextVMArgReg));
}
// advance spillOffsetVM and nextVMArgReg
nextVMArgReg++;
spillOffsetVM += BYTES_IN_STACKSLOT;
} else if (nextVMArgReg > LAST_VOLATILE_GPR.value()) {
if (dstSpilling) {
asmArg.emitLFD(FIRST_SCRATCH_FPR, spillOffsetVM, FP);
asmArg.emitSTFD(FIRST_SCRATCH_FPR, regOrSpilling, FP);
} else {
// this shouldnot happen, VM spills, OS has registers
asmArg.emitLWZ(GPR.lookup(regOrSpilling + 1), spillOffsetVM + 4, FP);
asmArg.emitLWZ(GPR.lookup(regOrSpilling), spillOffsetVM, FP);
}
spillOffsetVM += BYTES_IN_LONG;
}
} else if (types[arg].isLongType() && VM.BuildFor64Addr) {
// handle OS first
boolean dstSpilling;
// it is register number or spilling offset
int regOrSpilling = -1;
// 1. check if Linux register > 9
if (nextOSArgReg > LAST_OS_PARAMETER_GPR.value()) {
// goes to spilling area
dstSpilling = true;
/* NOTE: following adjustment is not stated in SVR4 ABI, but
* was implemented in GCC.
* -- Feng
*/
nextOSArgReg = LAST_OS_PARAMETER_GPR.value() + 1;
// do alignment and compute spilling offset
spillOffsetOS = (spillOffsetOS + 7) & -8;
regOrSpilling = spillOffsetOS;
spillOffsetOS += BYTES_IN_LONG;
} else {
// use registers
dstSpilling = false;
// rounds to odd
regOrSpilling = nextOSArgReg;
nextOSArgReg += 1;
}
// handle RVM source
if (nextVMArgReg <= LAST_VOLATILE_GPR.value()) {
// both parts in registers
if (dstSpilling) {
asmArg.emitSTD(GPR.lookup(nextVMArgReg), regOrSpilling, FP);
} else {
asmArg.emitMR(GPR.lookup(regOrSpilling), GPR.lookup(nextVMArgReg));
}
// advance register counting, Linux register number
// already advanced
nextVMArgReg += 1;
} else if (nextVMArgReg > LAST_VOLATILE_GPR.value()) {
if (dstSpilling) {
asmArg.emitLFD(FIRST_SCRATCH_FPR, spillOffsetVM, FP);
asmArg.emitSTFD(FIRST_SCRATCH_FPR, regOrSpilling, FP);
} else {
// this shouldnot happen, VM spills, OS has registers;
asmArg.emitLD(GPR.lookup(regOrSpilling), spillOffsetVM, FP);
}
spillOffsetVM += BYTES_IN_LONG;
}
} else if (types[arg].isReferenceType()) {
// For reference type, replace with handles before passing to native
GPR srcreg;
if (nextVMArgReg <= LAST_VOLATILE_GPR.value()) {
srcreg = GPR.lookup(nextVMArgReg++);
} else {
srcreg = REGISTER_ZERO;
asmArg.emitLAddr(srcreg, spillOffsetVM, FP);
spillOffsetVM += BYTES_IN_ADDRESS;
}
// Are we passing NULL?
asmArg.emitCMPI(srcreg, 0);
ForwardReference isNull = asmArg.emitForwardBC(EQ);
// NO: put it in the JNIRefs array and pass offset
asmArg.emitSTAddrU(srcreg, BYTES_IN_ADDRESS, KLUDGE_TI_REG);
if (nextOSArgReg <= LAST_OS_PARAMETER_GPR.value()) {
asmArg.emitSUBFC(GPR.lookup(nextOSArgReg), THREAD_REGISTER, KLUDGE_TI_REG);
} else {
asmArg.emitSUBFC(REGISTER_ZERO, THREAD_REGISTER, KLUDGE_TI_REG);
asmArg.emitSTAddr(REGISTER_ZERO, spillOffsetOS, FP);
}
ForwardReference done = asmArg.emitForwardB();
// YES: pass NULL (0)
isNull.resolve(asmArg);
if (nextOSArgReg <= LAST_OS_PARAMETER_GPR.value()) {
asmArg.emitLVAL(GPR.lookup(nextOSArgReg), 0);
} else {
asmArg.emitSTAddr(srcreg, spillOffsetOS, FP);
}
// JOIN PATHS
done.resolve(asmArg);
if (VM.BuildForSVR4ABI) {
if (nextOSArgReg <= LAST_OS_PARAMETER_GPR.value()) {
nextOSArgReg++;
} else {
spillOffsetOS += BYTES_IN_ADDRESS;
}
}
} else {
// (1a) fit in OS register, move the register
if (nextOSArgReg <= LAST_OS_PARAMETER_GPR.value()) {
if (VM.BuildForSVR4ABI) {
asmArg.emitMR(GPR.lookup(nextOSArgReg++), GPR.lookup(nextVMArgReg++));
} else {
asmArg.emitMR(GPR.lookup(nextOSArgReg), GPR.lookup(nextVMArgReg++));
}
} else if (nextVMArgReg <= LAST_VOLATILE_GPR.value()) {
// (1b) spill OS register, but still fit in VM register
asmArg.emitSTAddr(GPR.lookup(nextVMArgReg++), spillOffsetOS, FP);
if (VM.BuildForSVR4ABI) {
spillOffsetOS += BYTES_IN_ADDRESS;
}
} else {
// (1c) spill VM register
spillOffsetVM += BYTES_IN_STACKSLOT;
// retrieve arg from VM spill area
asmArg.emitLInt(REGISTER_ZERO, spillOffsetVM - BYTES_IN_INT, FP);
asmArg.emitSTAddr(REGISTER_ZERO, spillOffsetOS, FP);
if (VM.BuildForSVR4ABI) {
spillOffsetOS += BYTES_IN_ADDRESS;
}
}
}
}
// so that the move does not overwrite the parameters
for (int arg = asmForArgs.length - 1; arg >= 0; arg--) {
asm.appendInstructions(asmForArgs[arg].getMachineCodes());
}
}
}
use of org.jikesrvm.ppc.RegisterConstants.GPR in project JikesRVM by JikesRVM.
the class JNICompiler method storeParameters.
/**
* Map the arguments from RVM convention to OS convention,
* and replace all references with indexes into JNIRefs array.
* <p>
* Assumption on entry:
* <ul>
* <li>KLUDGE_TI_REG, THREAD_REGISTER and S1 are available for use as scratch register
* <li>the frame has been created, FP points to the new callee frame
* </ul>
* <p>
* Also update the JNIRefs array
*/
private static void storeParameters(Assembler asm, int frameSize, RVMMethod method, RVMClass klass) {
int nextOSArgReg, nextOSArgFloatReg, nextVMArgReg, nextVMArgFloatReg;
// offset to the spill area in the callee (OS frame):
int spillOffsetOS;
if (VM.BuildForPower64ELF_ABI) {
// 1st spill = JNIEnv, 2nd spill = class
spillOffsetOS = NATIVE_FRAME_HEADER_SIZE + 2 * BYTES_IN_STACKSLOT;
} else {
if (VM.VerifyAssertions)
VM._assert(VM.BuildForSVR4ABI);
spillOffsetOS = 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
TypeReference[] types = method.getParameterTypes();
// Set up the Reference table for GC
// TR <- JREFS array base
asm.emitLAddrOffset(THREAD_REGISTER, S0, Entrypoints.JNIRefsField.getOffset());
// TI <- JREFS current top
// JREFS offset for current TOP
asm.emitLIntOffset(KLUDGE_TI_REG, S0, Entrypoints.JNIRefsTopField.getOffset());
// convert into address
asm.emitADD(KLUDGE_TI_REG, THREAD_REGISTER, KLUDGE_TI_REG);
// 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.emitLIntOffset(S1, S0, Entrypoints.JNIRefsSavedFPField.getOffset());
asm.emitSTWU(S1, BYTES_IN_ADDRESS, // push prev frame ptr onto JNIRefs array
KLUDGE_TI_REG);
// compute offset for new TOP
asm.emitSUBFC(S1, THREAD_REGISTER, KLUDGE_TI_REG);
asm.emitSTWoffset(S1, S0, // save new TOP as new frame ptr in JNIEnv
Entrypoints.JNIRefsSavedFPField.getOffset());
// 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 OS callee Java caller OS 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
//
nextOSArgFloatReg = FIRST_OS_PARAMETER_FPR.value();
nextVMArgFloatReg = FIRST_VOLATILE_FPR.value();
// 1st reg = JNIEnv, 2nd reg = class/this
nextOSArgReg = FIRST_OS_PARAMETER_GPR.value() + 2;
if (method.isStatic()) {
nextVMArgReg = FIRST_VOLATILE_GPR.value();
} else {
// 1st reg = this, to be processed separately
nextVMArgReg = FIRST_VOLATILE_GPR.value() + 1;
}
// 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.value() <= LAST_VOLATILE_FPR.value());
if (VM.VerifyAssertions)
VM._assert(FIRST_OS_PARAMETER_GPR == FIRST_VOLATILE_GPR);
if (VM.VerifyAssertions)
VM._assert(LAST_OS_PARAMETER_GPR.value() <= LAST_VOLATILE_GPR.value());
generateParameterPassingCode(asm, types, nextVMArgReg, nextVMArgFloatReg, spillOffsetVM, nextOSArgReg, nextOSArgFloatReg, spillOffsetOS);
// Now add the 2 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)
GPR SECOND_OS_PARAMETER_GPR = GPR.lookup(FIRST_OS_PARAMETER_GPR.value() + 1);
if (method.isStatic()) {
// ASSMPTION: JTOC saved above in JNIEnv is still valid,
// used by following emitLAddrToc
Offset klassOffset = Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(klass.getClassForType()));
asm.emitLAddrToc(SECOND_OS_PARAMETER_GPR, klassOffset);
asm.emitSTAddrU(SECOND_OS_PARAMETER_GPR, BYTES_IN_ADDRESS, // append class ptr to end of JNIRefs array
KLUDGE_TI_REG);
// pass offset in bytes
asm.emitSUBFC(SECOND_OS_PARAMETER_GPR, THREAD_REGISTER, KLUDGE_TI_REG);
} else {
// append this ptr to end of JNIRefs array
asm.emitSTAddrU(T0, BYTES_IN_ADDRESS, KLUDGE_TI_REG);
// pass offset in bytes
asm.emitSUBFC(SECOND_OS_PARAMETER_GPR, THREAD_REGISTER, KLUDGE_TI_REG);
}
// store the new JNIRefs array TOP back into JNIEnv
// compute offset for the current TOP
asm.emitSUBFC(KLUDGE_TI_REG, THREAD_REGISTER, KLUDGE_TI_REG);
asm.emitSTWoffset(KLUDGE_TI_REG, S0, Entrypoints.JNIRefsTopField.getOffset());
}
Aggregations