Search in sources :

Example 71 with ForwardReference

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();
}
Also used : ForwardReference(org.jikesrvm.compilers.common.assembler.ForwardReference) GPR(org.jikesrvm.ia32.RegisterConstants.GPR) Assembler(org.jikesrvm.compilers.common.assembler.ia32.Assembler) Entrypoint(org.vmmagic.pragma.Entrypoint) Offset(org.vmmagic.unboxed.Offset)

Aggregations

ForwardReference (org.jikesrvm.compilers.common.assembler.ForwardReference)71 Offset (org.vmmagic.unboxed.Offset)13 TypeReference (org.jikesrvm.classloader.TypeReference)5 RVMClass (org.jikesrvm.classloader.RVMClass)4 Assembler (org.jikesrvm.compilers.common.assembler.ppc.Assembler)4 RVMMethod (org.jikesrvm.classloader.RVMMethod)3 GPR (org.jikesrvm.ia32.RegisterConstants.GPR)3 XMM (org.jikesrvm.ia32.RegisterConstants.XMM)3 InterfaceMethodSignature (org.jikesrvm.classloader.InterfaceMethodSignature)2 RVMArray (org.jikesrvm.classloader.RVMArray)2 Assembler (org.jikesrvm.compilers.common.assembler.ia32.Assembler)2 FloatingPointMachineRegister (org.jikesrvm.ia32.RegisterConstants.FloatingPointMachineRegister)2 JNICompiledMethod (org.jikesrvm.jni.JNICompiledMethod)2 Entrypoint (org.vmmagic.pragma.Entrypoint)2 Inline (org.vmmagic.pragma.Inline)2 Address (org.vmmagic.unboxed.Address)2 Atom (org.jikesrvm.classloader.Atom)1 FieldReference (org.jikesrvm.classloader.FieldReference)1 MethodReference (org.jikesrvm.classloader.MethodReference)1 RVMType (org.jikesrvm.classloader.RVMType)1