use of org.jikesrvm.compilers.common.assembler.ForwardReference in project JikesRVM by JikesRVM.
the class OutOfLineMachineCode method generateReflectiveMethodInvokerInstructions.
/**
* Machine code for reflective method invocation.
* <pre>
* VM compiled with NUM_PARAMETERS_GPRS == 0
* Registers taken at runtime:
* none
* Stack taken at runtime:
* hi-mem
* address of method entrypoint to be called
* address of gpr registers to be loaded
* address of fpr registers to be loaded
* address of parameters area in calling frame
* return address
* low-mem
*
* VM compiled with NUM_PARAMETERS_GPRS == 1
* T0 == address of method entrypoint to be called
* Stack taken at runtime:
* hi-mem
* space ???
* address of gpr registers to be loaded
* address of fpr registers to be loaded
* address of parameters area in calling frame
* return address
* low-mem
*
* VM compiled with NUM_PARAMETERS_GPRS == 2
* T0 == address of method entrypoint to be called
* T1 == address of gpr registers to be loaded
* Stack taken at runtime:
* hi-mem
* space ???
* space ???
* address of fpr registers to be loaded
* address of parameters area in calling frame
* return address
* low-mem
*
* Registers returned at runtime:
* standard return value conventions used
*
* Side effects at runtime:
* artificial stackframe created and destroyed
* volatile, and scratch registers destroyed
* </pre>
*
* @return instructions for the reflective method invoker
*/
private static CodeArray generateReflectiveMethodInvokerInstructions() {
Assembler asm = new Assembler(100);
int gprs;
Offset fpOffset = ArchEntrypoints.framePointerField.getOffset();
GPR T = T0;
gprs = NUM_PARAMETER_GPRS;
// we have exactly 5 paramaters, offset 0 from SP is the return address the
// parameters are at offsets 5 to 1
Offset offset = Offset.fromIntZeroExtend(5 << LG_WORDSIZE);
// logically equivalent to ParamaterRegisterUnload in the compiler
if (gprs > 0) {
gprs--;
if (VM.BuildFor32Addr) {
asm.emitMOV_RegDisp_Reg(SP, offset, T);
} else {
asm.emitMOV_RegDisp_Reg_Quad(SP, offset, T);
}
T = T1;
offset = offset.minus(WORDSIZE);
}
if (gprs > 0) {
if (VM.BuildFor32Addr) {
asm.emitMOV_RegDisp_Reg(SP, offset, T);
} else {
asm.emitMOV_RegDisp_Reg_Quad(SP, offset, T);
}
}
/* available registers S0, T0, T1 */
/* push a new frame */
// link this frame with next
asm.emitPUSH_RegDisp(TR, fpOffset);
if (VM.BuildFor32Addr) {
// establish base of new frame
asm.emitMOV_RegDisp_Reg(THREAD_REGISTER, fpOffset, SP);
asm.emitPUSH_Imm(INVISIBLE_METHOD_ID);
asm.emitADD_Reg_Imm(SP, STACKFRAME_BODY_OFFSET.toInt());
} else {
// establish base of new frame
asm.emitMOV_RegDisp_Reg_Quad(THREAD_REGISTER, fpOffset, SP);
asm.emitPUSH_Imm(INVISIBLE_METHOD_ID);
asm.emitADD_Reg_Imm_Quad(SP, STACKFRAME_BODY_OFFSET.toInt());
}
/* write parameters on stack
* move data from memory addressed by Paramaters array, the fourth
* parameter to this, into the stack.
* SP target address
* S0 source address
* T1 length
* T0 scratch
*/
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(S0, THREAD_REGISTER, fpOffset);
// S0 <- Parameters
asm.emitMOV_Reg_RegDisp(S0, S0, PARAMS_FP_OFFSET);
// T1 <- Parameters.length()
asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset());
// length == 0 ?
asm.emitCMP_Reg_Imm(T1, 0);
} else {
asm.emitMOV_Reg_RegDisp_Quad(S0, THREAD_REGISTER, fpOffset);
// S0 <- Parameters
asm.emitMOV_Reg_RegDisp_Quad(S0, S0, PARAMS_FP_OFFSET);
if (ARRAY_LENGTH_BYTES == 4) {
// T1 <- Parameters.length()
asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset());
// length == 0 ?
asm.emitCMP_Reg_Imm(T1, 0);
} else {
// T1 <- Parameters.length()
asm.emitMOV_Reg_RegDisp_Quad(T1, S0, ObjectModel.getArrayLengthOffset());
// length == 0 ?
asm.emitCMP_Reg_Imm_Quad(T1, 0);
}
}
int parameterLoopLabel = asm.getMachineCodeIndex();
// done? --> branch to end
ForwardReference fr1 = asm.forwardJcc(EQ);
if (VM.BuildFor32Addr) {
// T0 <- Paramaters[i]
asm.emitMOV_Reg_RegInd(T0, S0);
} else {
// T0 <- Paramaters[i]
asm.emitMOV_Reg_RegInd_Quad(T0, S0);
}
// mem[j++] <- Parameters[i]
asm.emitPUSH_Reg(T0);
if (VM.BuildFor32Addr) {
// i++
asm.emitADD_Reg_Imm(S0, WORDSIZE);
} else {
// i++
asm.emitADD_Reg_Imm_Quad(S0, WORDSIZE);
}
if (ARRAY_LENGTH_BYTES == 4) {
// length--
asm.emitADD_Reg_Imm(T1, -1);
} else {
// length--
asm.emitADD_Reg_Imm_Quad(T1, -1);
}
asm.emitJMP_Imm(parameterLoopLabel);
// end of the loop
fr1.resolve(asm);
if (SSE2_FULL) {
/* write fprs onto fprs registers */
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(S0, THREAD_REGISTER, fpOffset);
// T0 <- FPRs
asm.emitMOV_Reg_RegDisp(T0, S0, FPRS_FP_OFFSET);
// T1 <- FPRs.length()
asm.emitMOV_Reg_RegDisp(T1, T0, ObjectModel.getArrayLengthOffset());
// S0 <- FPRmeta
asm.emitMOV_Reg_RegDisp(S0, S0, FPRMETA_FP_OFFSET);
} else {
asm.emitMOV_Reg_RegDisp_Quad(S0, THREAD_REGISTER, fpOffset);
// T0 <- FPRs
asm.emitMOV_Reg_RegDisp_Quad(T0, S0, FPRS_FP_OFFSET);
if (ARRAY_LENGTH_BYTES == 4) {
// T1 <- FPRs.length()
asm.emitMOV_Reg_RegDisp(T1, T0, ObjectModel.getArrayLengthOffset());
} else {
// T1 <- FPRs.length()
asm.emitMOV_Reg_RegDisp_Quad(T1, T0, ObjectModel.getArrayLengthOffset());
}
// S0 <- FPRmeta
asm.emitMOV_Reg_RegDisp_Quad(S0, S0, FPRMETA_FP_OFFSET);
}
if (VM.VerifyAssertions)
VM._assert(NUM_PARAMETER_FPRS <= 4);
ForwardReference fr_next;
// length == 0 ?
asm.emitCMP_Reg_Imm(T1, 0);
ForwardReference fpr_r1 = asm.forwardJcc(EQ);
asm.emitMOVSD_Reg_RegInd(XMM0, T0);
asm.emitCMP_RegInd_Imm_Byte(S0, 0);
fr_next = asm.forwardJcc(NE);
asm.emitCVTSD2SS_Reg_Reg(XMM0, XMM0);
fr_next.resolve(asm);
// length == 0 ?
asm.emitSUB_Reg_Imm(T1, 1);
ForwardReference fpr_r2 = asm.forwardJcc(EQ);
asm.emitMOVSD_Reg_RegDisp(XMM1, T0, Offset.fromIntZeroExtend(BYTES_IN_DOUBLE));
asm.emitCMP_RegDisp_Imm_Byte(S0, Offset.fromIntZeroExtend(1), 0);
fr_next = asm.forwardJcc(NE);
asm.emitCVTSD2SS_Reg_Reg(XMM1, XMM1);
fr_next.resolve(asm);
// length == 0 ?
asm.emitSUB_Reg_Imm(T1, 1);
ForwardReference fpr_r3 = asm.forwardJcc(EQ);
asm.emitMOVSD_Reg_RegDisp(XMM2, T0, Offset.fromIntZeroExtend(BYTES_IN_DOUBLE * 2));
asm.emitCMP_RegDisp_Imm_Byte(S0, Offset.fromIntZeroExtend(2), 0);
fr_next = asm.forwardJcc(NE);
asm.emitCVTSD2SS_Reg_Reg(XMM2, XMM2);
fr_next.resolve(asm);
// length == 0 ?
asm.emitSUB_Reg_Imm(T1, 1);
ForwardReference fpr_r4 = asm.forwardJcc(EQ);
asm.emitMOVSD_Reg_RegDisp(XMM3, T0, Offset.fromIntZeroExtend(BYTES_IN_DOUBLE * 3));
asm.emitCMP_RegDisp_Imm_Byte(S0, Offset.fromIntZeroExtend(3), 0);
fr_next = asm.forwardJcc(NE);
asm.emitCVTSD2SS_Reg_Reg(XMM3, XMM3);
fr_next.resolve(asm);
fpr_r1.resolve(asm);
fpr_r2.resolve(asm);
fpr_r3.resolve(asm);
fpr_r4.resolve(asm);
} else {
if (VM.VerifyAssertions)
VM._assert(VM.BuildFor32Addr);
/* write fprs onto fprs registers */
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(S0, THREAD_REGISTER, fpOffset);
} else {
asm.emitMOV_Reg_RegDisp_Quad(S0, THREAD_REGISTER, fpOffset);
}
// S0 <- FPRs
asm.emitMOV_Reg_RegDisp(S0, S0, FPRS_FP_OFFSET);
// T1 <- FPRs.length()
asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset());
// length in bytes
asm.emitSHL_Reg_Imm(T1, LG_WORDSIZE + 1);
// S0 <- last FPR + 8
asm.emitADD_Reg_Reg(S0, T1);
// length == 0 ?
asm.emitCMP_Reg_Imm(T1, 0);
int fprsLoopLabel = asm.getMachineCodeIndex();
// done? --> branch to end
ForwardReference fr2 = asm.forwardJcc(EQ);
// i--
asm.emitSUB_Reg_Imm(S0, 2 * WORDSIZE);
// frp[fpr_sp++] <-FPRs[i]
asm.emitFLD_Reg_RegInd_Quad(FP0, S0);
// length--
asm.emitSUB_Reg_Imm(T1, 2 * WORDSIZE);
asm.emitJMP_Imm(fprsLoopLabel);
// end of the loop
fr2.resolve(asm);
}
/* write gprs: S0 = Base address of GPRs[], T1 = GPRs.length */
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(S0, THREAD_REGISTER, fpOffset);
// S0 <- GPRs
asm.emitMOV_Reg_RegDisp(S0, S0, GPRS_FP_OFFSET);
// T1 <- GPRs.length()
asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset());
// length == 0 ?
asm.emitCMP_Reg_Imm(T1, 0);
} else {
asm.emitMOV_Reg_RegDisp_Quad(S0, THREAD_REGISTER, fpOffset);
// S0 <- GPRs
asm.emitMOV_Reg_RegDisp_Quad(S0, S0, GPRS_FP_OFFSET);
if (ARRAY_LENGTH_BYTES == 4) {
// T1 <- GPRs.length()
asm.emitMOV_Reg_RegDisp(T1, S0, ObjectModel.getArrayLengthOffset());
// length == 0 ?
asm.emitCMP_Reg_Imm(T1, 0);
} else {
// T1 <- GPRs.length()
asm.emitMOV_Reg_RegDisp_Quad(T1, S0, ObjectModel.getArrayLengthOffset());
// length == 0 ?
asm.emitCMP_Reg_Imm_Quad(T1, 0);
}
}
// result 0 --> branch to end
ForwardReference fr3 = asm.forwardJcc(EQ);
if (VM.BuildFor32Addr) {
// T0 <- GPRs[0]
asm.emitMOV_Reg_RegInd(T0, S0);
// S0 += WORDSIZE
asm.emitADD_Reg_Imm(S0, WORDSIZE);
// T1--
asm.emitADD_Reg_Imm(T1, -1);
} else {
// T0 <- GPRs[0]
asm.emitMOV_Reg_RegInd_Quad(T0, S0);
// S0 += WORDSIZE
asm.emitADD_Reg_Imm_Quad(S0, WORDSIZE);
// T1--
asm.emitADD_Reg_Imm_Quad(T1, -1);
}
// result 0 --> branch to end
ForwardReference fr4 = asm.forwardJcc(EQ);
if (VM.BuildFor32Addr) {
// T1 <- GPRs[1]
asm.emitMOV_Reg_RegInd(T1, S0);
} else {
// T1 <- GPRs[1]
asm.emitMOV_Reg_RegInd_Quad(T1, S0);
}
fr3.resolve(asm);
fr4.resolve(asm);
/* branch to method. On a good day we might even be back */
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(S0, THREAD_REGISTER, fpOffset);
// S0 <- code
asm.emitMOV_Reg_RegDisp(S0, S0, CODE_FP_OFFSET);
} else {
asm.emitMOV_Reg_RegDisp_Quad(S0, THREAD_REGISTER, fpOffset);
// S0 <- code
asm.emitMOV_Reg_RegDisp_Quad(S0, S0, CODE_FP_OFFSET);
}
// go there
asm.emitCALL_Reg(S0);
// add back in the initial SP to FP delta to get SP to be a framepointer again!
if (VM.BuildFor32Addr) {
asm.emitADD_Reg_Imm(SP, -STACKFRAME_BODY_OFFSET.toInt() + WORDSIZE);
} else {
asm.emitADD_Reg_Imm_Quad(SP, -STACKFRAME_BODY_OFFSET.toInt() + WORDSIZE);
}
asm.emitPOP_RegDisp(TR, fpOffset);
// again, exactly 5 parameters
asm.emitRET_Imm(5 << LG_WORDSIZE);
return asm.getMachineCodes();
}
Aggregations