Search in sources :

Example 6 with GPR

use of org.jikesrvm.ia32.RegisterConstants.GPR in project JikesRVM by JikesRVM.

the class OptExecutionStateExtractor method dumpRegisterContent.

@SuppressWarnings("unused")
private static void dumpRegisterContent(WordArray gprs) {
    for (GPR reg : GPR.values()) {
        VM.sysWrite(reg.toString());
        VM.sysWrite(" = ");
        VM.sysWriteln(gprs.get(reg.value()));
    }
}
Also used : GPR(org.jikesrvm.ia32.RegisterConstants.GPR)

Example 7 with GPR

use of org.jikesrvm.ia32.RegisterConstants.GPR in project JikesRVM by JikesRVM.

the class OptExecutionStateExtractor method restoreValuesFromOptSaveVolatile.

/* OptSaveVolatile has different stack layout from DynamicBridge
    * Have to separately recover them now, but there should be unified
    * later on.
    *
    *    |----------|
    *    |   NON    |
    *    |Volatiles |
    *    |          | <-- volatile offset
    *    |Volatiles |
    *    |          |
    *    |FPR states|
    *    |__________|  ___ FP
  */
private void restoreValuesFromOptSaveVolatile(byte[] stack, Offset osrFPoff, TempRegisters registers, int regmap, CompiledMethod cm) {
    OptCompiledMethod tsfromCM = (OptCompiledMethod) cm;
    boolean saveVolatile = tsfromCM.isSaveVolatile();
    if (VM.VerifyAssertions) {
        VM._assert(saveVolatile);
    }
    WordArray gprs = registers.gprs;
    // enter critical section
    // precall methods potientially causing dynamic compilation
    int firstNonVolatile = tsfromCM.getFirstNonVolatileGPR();
    int nonVolatiles = tsfromCM.getNumberOfNonvolatileGPRs();
    int nonVolatileOffset = tsfromCM.getUnsignedNonVolatileOffset() + (nonVolatiles - 1) * BYTES_IN_STACKSLOT;
    VM.disableGC();
    // recover nonvolatile GPRs
    for (int i = firstNonVolatile + nonVolatiles - 1; i >= firstNonVolatile; i--) {
        gprs.set(NONVOLATILE_GPRS[i].value(), Magic.objectAsAddress(stack).loadWord(osrFPoff.minus(nonVolatileOffset)));
        nonVolatileOffset -= BYTES_IN_STACKSLOT;
    }
    // restore with VOLATILES yet
    int volatileOffset = nonVolatileOffset;
    for (int i = NUM_VOLATILE_GPRS - 1; i >= 0; i--) {
        gprs.set(VOLATILE_GPRS[i].value(), Magic.objectAsAddress(stack).loadWord(osrFPoff.minus(volatileOffset)));
        volatileOffset -= BYTES_IN_STACKSLOT;
    }
    // powerPC starts from register 1
    for (int i = 0; i < NUM_GPRS; i++) {
        if (EncodedOSRMap.registerIsSet(regmap, i)) {
            registers.objs[i] = Magic.addressAsObject(registers.gprs.get(i).toAddress());
        }
    }
    VM.enableGC();
    if (VM.TraceOnStackReplacement) {
        for (GPR reg : GPR.values()) {
            VM.sysWrite(reg.toString());
            VM.sysWrite(" = ");
            VM.sysWrite(registers.gprs.get(reg.value()).toAddress());
            VM.sysWriteln();
        }
    }
}
Also used : OptCompiledMethod(org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod) WordArray(org.vmmagic.unboxed.WordArray) GPR(org.jikesrvm.ia32.RegisterConstants.GPR)

Example 8 with GPR

use of org.jikesrvm.ia32.RegisterConstants.GPR in project JikesRVM by JikesRVM.

the class JNICompiler method generateEpilogForJNIMethod.

/**
 * Handles the C to Java transition:  JNI methods in JNIFunctions.java.
 * Creates an epilogue for the baseline compiler.
 *
 * @param asm the assembler to use
 * @param method the method that's being compiled
 */
public static void generateEpilogForJNIMethod(Assembler asm, RVMMethod method) {
    if (VM.BuildFor32Addr) {
        // if returning long, switch the order of the hi/lo word in T0 and T1
        if (method.getReturnType().isLongType()) {
            asm.emitPUSH_Reg(T1);
            asm.emitMOV_Reg_Reg(T1, T0);
            asm.emitPOP_Reg(T0);
        } else {
            if (SSE2_FULL && VM.BuildFor32Addr) {
                // Marshall from XMM0 -> FP0
                if (method.getReturnType().isDoubleType()) {
                    if (VM.VerifyAssertions)
                        VM._assert(VM.BuildFor32Addr);
                    asm.emitMOVSD_RegDisp_Reg(THREAD_REGISTER, Entrypoints.scratchStorageField.getOffset(), XMM0);
                    asm.emitFLD_Reg_RegDisp_Quad(FP0, THREAD_REGISTER, Entrypoints.scratchStorageField.getOffset());
                } else if (method.getReturnType().isFloatType()) {
                    if (VM.VerifyAssertions)
                        VM._assert(VM.BuildFor32Addr);
                    asm.emitMOVSS_RegDisp_Reg(THREAD_REGISTER, Entrypoints.scratchStorageField.getOffset(), XMM0);
                    asm.emitFLD_Reg_RegDisp(FP0, THREAD_REGISTER, Entrypoints.scratchStorageField.getOffset());
                }
            }
        }
    }
    // S0 <- JNIEnvironment
    if (VM.BuildFor32Addr) {
        asm.emitMOV_Reg_RegDisp(S0, THREAD_REGISTER, Entrypoints.jniEnvField.getOffset());
    } else {
        asm.emitMOV_Reg_RegDisp_Quad(S0, THREAD_REGISTER, Entrypoints.jniEnvField.getOffset());
    }
    // set jniEnv TopJavaFP using value saved in frame in prolog
    if (VM.BuildFor32Addr) {
        // EDI<-saved TopJavaFP (offset)
        asm.emitMOV_Reg_RegDisp(EDI, EBP, SAVED_JAVA_FP_OFFSET);
        // change offset from FP into address
        asm.emitADD_Reg_Reg(EDI, EBP);
        // jniEnv.TopJavaFP <- EDI
        asm.emitMOV_RegDisp_Reg(S0, Entrypoints.JNITopJavaFPField.getOffset(), EDI);
    } else {
        // EDI<-saved TopJavaFP (offset)
        asm.emitMOV_Reg_RegDisp_Quad(EDI, EBP, SAVED_JAVA_FP_OFFSET);
        // change offset from FP into address
        asm.emitADD_Reg_Reg_Quad(EDI, EBP);
        // jniEnv.TopJavaFP <- EDI
        asm.emitMOV_RegDisp_Reg_Quad(S0, Entrypoints.JNITopJavaFPField.getOffset(), EDI);
    }
    // NOTE: we could save the TR in the JNI env, but no need, that would have
    // already been done.
    // what's going on here:
    // - SP and EBP have important stuff in them, but that's fine, since
    // a call will restore SP and EBP is non-volatile for RVM code
    // - TR still refers to the thread
    // save return values
    asm.emitPUSH_Reg(T0);
    asm.emitPUSH_Reg(T1);
    // attempt to change the thread state to IN_JNI
    asm.emitMOV_Reg_Imm(T0, RVMThread.IN_JAVA);
    asm.emitMOV_Reg_Imm(T1, RVMThread.IN_JNI);
    asm.emitLockNextInstruction();
    asm.emitCMPXCHG_RegDisp_Reg(THREAD_REGISTER, Entrypoints.execStatusField.getOffset(), T1);
    // if success, skip the slow path call
    ForwardReference doneEnterJNIRef = asm.forwardJcc(EQ);
    // fast path failed, make the call
    asm.generateJTOCcall(Entrypoints.enterJNIBlockedFromJNIFunctionCallMethod.getOffset());
    // OK - we reach here when we have set the state to IN_JNI
    doneEnterJNIRef.resolve(asm);
    // restore return values
    asm.emitPOP_Reg(T1);
    asm.emitPOP_Reg(T0);
    // reload native/C nonvolatile regs - saved in prolog
    for (FloatingPointMachineRegister r : NATIVE_NONVOLATILE_FPRS) {
        // TODO: we assume non-volatile will hold at most a double
        if (r instanceof XMM) {
            asm.emitMOVSD_Reg_RegInd((XMM) r, SP);
        } else {
            // NB this will fail for anything other than FPR0
            asm.emitFLD_Reg_RegInd_Quad((FPR) r, SP);
        }
        // adjust space for double
        asm.emitPOP_Reg(T0);
        asm.emitPOP_Reg(T0);
    }
    // nonvolatile push as the 1st instruction of the prologue
    for (int i = NATIVE_NONVOLATILE_GPRS.length - 1; i >= 0; i--) {
        GPR r = NATIVE_NONVOLATILE_GPRS[i];
        asm.emitPOP_Reg(r);
    }
    // Discard JNIEnv, CMID and outer most native frame pointer
    if (VM.BuildFor32Addr) {
        // discard current stack frame
        asm.emitADD_Reg_Imm(SP, 3 * WORDSIZE);
    } else {
        // discard current stack frame
        asm.emitADD_Reg_Imm_Quad(SP, 3 * WORDSIZE);
    }
    // return to caller
    asm.emitRET();
}
Also used : ForwardReference(org.jikesrvm.compilers.common.assembler.ForwardReference) FloatingPointMachineRegister(org.jikesrvm.ia32.RegisterConstants.FloatingPointMachineRegister) GPR(org.jikesrvm.ia32.RegisterConstants.GPR) XMM(org.jikesrvm.ia32.RegisterConstants.XMM)

Example 9 with GPR

use of org.jikesrvm.ia32.RegisterConstants.GPR in project JikesRVM by JikesRVM.

the class JNICompiler method generateGlueCodeForJNIMethod.

/**
 * Handles the C to Java transition:  JNI methods in JNIFunctions.java.
 * Creates a prologue for the baseline compiler.
 * <pre>
 * NOTE:
 *   -We need THREAD_REGISTER to access Java environment; we can get it from
 *    the JNIEnv* (which is an interior pointer to the JNIEnvironment)
 *   -Unlike the powerPC scheme which has a special prolog preceding
 *    the normal Java prolog, the Intel scheme replaces the Java prolog
 *    completely with the special prolog
 *
 *            Stack on entry            Stack at end of prolog after call
 *             high memory                       high memory
 *            |            |                   |            |
 *    EBP -&gt;  |saved FP    |                   |saved FP    |
 *            |  ...       |                   |  ...       |
 *            |            |                   |            |
 *            |arg n-1     |                   |arg n-1     |
 * native     |  ...       |                   |  ...       |
 * caller     |arg 0       | JNIEnv*           |arg 0       | JNIEnvironment
 *    ESP -&gt;  |return addr |                   |return addr |
 *            |            |           EBP -&gt;  |saved FP    | outer most native frame pointer
 *            |            |                   |methodID    | normal MethodID for JNI function
 *            |            |                   |saved JavaFP| offset to preceeding java frame
 *            |            |                   |saved nonvol| to be used for nonvolatile storage
 *            |            |                   |  ...       |   including ebp on entry
 *            |            |                   |arg 0       | copied in reverse order (JNIEnvironment)
 *            |            |                   |  ...       |
 *            |            |           ESP -&gt;  |arg n-1     |
 *            |            |                   |            | normally compiled Java code continue
 *            |            |                   |            |
 *            |            |                   |            |
 *            |            |                   |            |
 *             low memory                        low memory
 * </pre>
 *
 * @param asm the assembler to use
 * @param method the method that's being compiled (i.e. the method which is a bridge
 *  from native).
 * @param methodID the id of the compiled method
 */
public static void generateGlueCodeForJNIMethod(Assembler asm, NormalMethod method, int methodID) {
    // Variable tracking the depth of the stack as we generate the prologue
    int stackDepth = 0;
    // 2nd word of header = space for frame pointer
    if (VM.VerifyAssertions)
        VM._assert(STACKFRAME_FRAME_POINTER_OFFSET.toInt() == stackDepth << LG_WORDSIZE);
    asm.emitPUSH_Reg(EBP);
    stackDepth--;
    // start new frame:  set FP to point to the new frame
    if (VM.BuildFor32Addr) {
        asm.emitMOV_Reg_Reg(EBP, SP);
    } else {
        asm.emitMOV_Reg_Reg_Quad(EBP, SP);
    }
    // set 3rd word of header: method ID
    if (VM.VerifyAssertions)
        VM._assert(STACKFRAME_METHOD_ID_OFFSET.toInt() == stackDepth << LG_WORDSIZE);
    asm.emitPUSH_Imm(methodID);
    stackDepth--;
    // buy space for the SAVED_JAVA_FP
    if (VM.VerifyAssertions)
        VM._assert(STACKFRAME_BODY_OFFSET.toInt() == stackDepth << LG_WORDSIZE);
    asm.emitPUSH_Reg(T0);
    stackDepth--;
    // store non-volatiles
    for (GPR r : NATIVE_NONVOLATILE_GPRS) {
        if (r != EBP) {
            asm.emitPUSH_Reg(r);
        } else {
            // save original EBP value
            asm.emitPUSH_RegInd(EBP);
        }
        stackDepth--;
    }
    for (FloatingPointMachineRegister r : NATIVE_NONVOLATILE_FPRS) {
        // TODO: we assume non-volatile will hold at most a double
        // adjust space for double
        asm.emitPUSH_Reg(T0);
        asm.emitPUSH_Reg(T0);
        stackDepth -= 2;
        if (r instanceof XMM) {
            asm.emitMOVSD_RegInd_Reg(SP, (XMM) r);
        } else {
            // NB this will fail for anything other than FPR0
            asm.emitFST_RegInd_Reg_Quad(SP, (FPR) r);
        }
    }
    if (VM.VerifyAssertions) {
        boolean b = stackDepth << LG_WORDSIZE == STACKFRAME_BODY_OFFSET.toInt() - (SAVED_GPRS_FOR_JNI << LG_WORDSIZE);
        if (!b) {
            String msg = "of2fp=" + stackDepth + " sg4j=" + SAVED_GPRS_FOR_JNI;
            VM._assert(VM.NOT_REACHED, msg);
        }
    }
    // Adjust first param from JNIEnv* to JNIEnvironment.
    final Offset firstStackArgOffset = Offset.fromIntSignExtend(2 * WORDSIZE);
    if (jniExternalFunctionsFieldOffset != 0) {
        if (NATIVE_PARAMETER_GPRS.length > 0) {
            if (VM.BuildFor32Addr) {
                asm.emitSUB_Reg_Imm(NATIVE_PARAMETER_GPRS[0], jniExternalFunctionsFieldOffset);
            } else {
                asm.emitSUB_Reg_Imm_Quad(NATIVE_PARAMETER_GPRS[0], jniExternalFunctionsFieldOffset);
            }
        } else {
            if (VM.BuildFor32Addr) {
                asm.emitSUB_RegDisp_Imm(EBP, firstStackArgOffset, jniExternalFunctionsFieldOffset);
            } else {
                asm.emitSUB_RegDisp_Imm_Quad(EBP, firstStackArgOffset, jniExternalFunctionsFieldOffset);
            }
        }
    }
    // copy the arguments in reverse order
    // does NOT include implicit this or class ptr
    final TypeReference[] argTypes = method.getParameterTypes();
    Offset stackArgOffset = firstStackArgOffset;
    // negative value relative to EBP
    final int startOfStackedArgs = stackDepth + 1;
    int argGPR = 0;
    int argFPR = 0;
    for (TypeReference argType : argTypes) {
        if (argType.isFloatType()) {
            if (argFPR < NATIVE_PARAMETER_FPRS.length) {
                // adjust stack
                asm.emitPUSH_Reg(T0);
                if (VM.BuildForSSE2) {
                    asm.emitMOVSS_RegInd_Reg(SP, (XMM) NATIVE_PARAMETER_FPRS[argFPR]);
                } else {
                    asm.emitFSTP_RegInd_Reg(SP, FP0);
                }
                argFPR++;
            } else {
                asm.emitPUSH_RegDisp(EBP, stackArgOffset);
                stackArgOffset = stackArgOffset.plus(WORDSIZE);
            }
            stackDepth--;
        } else if (argType.isDoubleType()) {
            if (argFPR < NATIVE_PARAMETER_FPRS.length) {
                // adjust stack
                asm.emitPUSH_Reg(T0);
                asm.emitPUSH_Reg(T0);
                if (VM.BuildForSSE2) {
                    asm.emitMOVSD_RegInd_Reg(SP, (XMM) NATIVE_PARAMETER_FPRS[argFPR]);
                } else {
                    asm.emitFSTP_RegInd_Reg_Quad(SP, FP0);
                }
                argFPR++;
            } else {
                if (VM.BuildFor32Addr) {
                    asm.emitPUSH_RegDisp(EBP, stackArgOffset.plus(WORDSIZE));
                    asm.emitPUSH_RegDisp(EBP, stackArgOffset);
                    stackArgOffset = stackArgOffset.plus(2 * WORDSIZE);
                } else {
                    // adjust stack
                    asm.emitPUSH_Reg(T0);
                    asm.emitPUSH_RegDisp(EBP, stackArgOffset);
                    stackArgOffset = stackArgOffset.plus(WORDSIZE);
                }
            }
            stackDepth -= 2;
        } else if (argType.isLongType()) {
            if (VM.BuildFor32Addr) {
                if (argGPR + 1 < NATIVE_PARAMETER_GPRS.length) {
                    asm.emitPUSH_Reg(NATIVE_PARAMETER_GPRS[argGPR]);
                    asm.emitPUSH_Reg(NATIVE_PARAMETER_GPRS[argGPR + 1]);
                    argGPR += 2;
                } else if (argGPR < NATIVE_PARAMETER_GPRS.length) {
                    asm.emitPUSH_RegDisp(EBP, stackArgOffset);
                    asm.emitPUSH_Reg(NATIVE_PARAMETER_GPRS[argGPR]);
                    argGPR++;
                    stackArgOffset = stackArgOffset.plus(WORDSIZE);
                } else {
                    asm.emitPUSH_RegDisp(EBP, stackArgOffset.plus(WORDSIZE));
                    asm.emitPUSH_RegDisp(EBP, stackArgOffset);
                    stackArgOffset = stackArgOffset.plus(WORDSIZE * 2);
                }
                stackDepth -= 2;
            } else {
                // adjust stack
                asm.emitPUSH_Reg(T0);
                if (argGPR < NATIVE_PARAMETER_GPRS.length) {
                    asm.emitPUSH_Reg(NATIVE_PARAMETER_GPRS[argGPR]);
                    argGPR++;
                } else {
                    asm.emitPUSH_RegDisp(EBP, stackArgOffset);
                    stackDepth -= 2;
                    stackArgOffset = stackArgOffset.plus(WORDSIZE);
                }
                stackDepth -= 2;
            }
        } else {
            // expect integer arguments
            if (argGPR < NATIVE_PARAMETER_GPRS.length) {
                asm.emitPUSH_Reg(NATIVE_PARAMETER_GPRS[argGPR]);
                argGPR++;
            } else {
                asm.emitPUSH_RegDisp(EBP, stackArgOffset);
                stackArgOffset = stackArgOffset.plus(WORDSIZE);
            }
            stackDepth--;
        }
    }
    // Restore JTOC register
    if (JTOC_REGISTER != null) {
        asm.emitMOV_Reg_Imm_Quad(JTOC_REGISTER, BootRecord.the_boot_record.tocRegister.toLong());
    }
    // START of code sequence to atomically change thread status from
    // IN_JNI to IN_JAVA, looping in a call to
    // RVMThread.leaveJNIBlockedFromJNIFunctionCallMethod if
    // BLOCKED_IN_NATIVE
    // backward branch label
    int retryLabel = asm.getMachineCodeIndex();
    // Restore THREAD_REGISTER from JNIEnvironment
    if (VM.BuildFor32Addr) {
        // pick up arg 0 (from our frame)
        asm.emitMOV_Reg_RegDisp(EBX, EBP, Offset.fromIntSignExtend((startOfStackedArgs - 1) * WORDSIZE));
        asm.emitMOV_Reg_RegDisp(THREAD_REGISTER, EBX, Entrypoints.JNIEnvSavedTRField.getOffset());
    } else {
        // pick up arg 0 (from our frame)
        asm.emitMOV_Reg_RegDisp_Quad(EBX, EBP, Offset.fromIntSignExtend((startOfStackedArgs - 1) * WORDSIZE));
        asm.emitMOV_Reg_RegDisp_Quad(THREAD_REGISTER, EBX, Entrypoints.JNIEnvSavedTRField.getOffset());
    }
    // what we need to keep in mind at this point:
    // - EBX has JNI env (but it's nonvolatile)
    // - EBP has the FP (but it's nonvolatile)
    // - stack has the args but not the locals
    // - TR has been restored
    // attempt to change the thread state to IN_JAVA
    asm.emitMOV_Reg_Imm(T0, RVMThread.IN_JNI);
    asm.emitMOV_Reg_Imm(T1, RVMThread.IN_JAVA);
    asm.emitLockNextInstruction();
    asm.emitCMPXCHG_RegDisp_Reg(THREAD_REGISTER, Entrypoints.execStatusField.getOffset(), T1);
    // if we succeeded, move on, else go into slow path
    ForwardReference doneLeaveJNIRef = asm.forwardJcc(EQ);
    // make the slow call
    asm.generateJTOCcall(Entrypoints.leaveJNIBlockedFromJNIFunctionCallMethod.getOffset());
    // arrive here when we've switched to IN_JAVA
    doneLeaveJNIRef.resolve(asm);
    // END of code sequence to change state from IN_JNI to IN_JAVA
    // status is now IN_JAVA. GC can not occur while we execute on a processor
    // in this state, so it is safe to access fields of objects.
    // RVM TR register has been restored and EBX contains a pointer to
    // the thread's JNIEnvironment.
    // done saving, bump SP to reserve room for the local variables
    // SP should now be at the point normally marked as emptyStackOffset
    int numLocalVariables = method.getLocalWords() - method.getParameterWords();
    // TODO: optimize this space adjustment
    if (VM.BuildFor32Addr) {
        asm.emitSUB_Reg_Imm(SP, (numLocalVariables << LG_WORDSIZE));
    } else {
        asm.emitSUB_Reg_Imm_Quad(SP, (numLocalVariables << LG_WORDSIZE));
    }
    // frame of JNIFunction
    if (VM.BuildFor32Addr) {
        asm.emitMOV_Reg_RegDisp(S0, EBX, Entrypoints.JNITopJavaFPField.getOffset());
    } else {
        asm.emitMOV_Reg_RegDisp_Quad(S0, EBX, Entrypoints.JNITopJavaFPField.getOffset());
    }
    // get offset from current FP and save in hdr of current frame
    if (VM.BuildFor32Addr) {
        asm.emitSUB_Reg_Reg(S0, EBP);
        asm.emitMOV_RegDisp_Reg(EBP, SAVED_JAVA_FP_OFFSET, S0);
    } else {
        asm.emitSUB_Reg_Reg_Quad(S0, EBP);
        asm.emitMOV_RegDisp_Reg_Quad(EBP, SAVED_JAVA_FP_OFFSET, S0);
    }
    // clobber the saved frame pointer with that from the JNIEnvironment (work around for omit-frame-pointer)
    if (VM.BuildFor32Addr) {
        asm.emitMOV_Reg_RegDisp(S0, EBX, Entrypoints.JNIEnvBasePointerOnEntryToNative.getOffset());
        asm.emitMOV_RegInd_Reg(EBP, S0);
    } else {
        asm.emitMOV_Reg_RegDisp_Quad(S0, EBX, Entrypoints.JNIEnvBasePointerOnEntryToNative.getOffset());
        asm.emitMOV_RegInd_Reg_Quad(EBP, S0);
    }
    // put framePointer in Thread following Jikes RVM conventions.
    if (VM.BuildFor32Addr) {
        asm.emitMOV_RegDisp_Reg(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset(), EBP);
    } else {
        asm.emitMOV_RegDisp_Reg_Quad(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset(), EBP);
    }
// at this point: TR has been restored &
// processor status = IN_JAVA,
// arguments for the call have been setup, space on the stack for locals
// has been acquired.
// finally proceed with the normal Java compiled code
// skip the thread switch test for now, see BaselineCompilerImpl.genThreadSwitchTest(true)
// asm.emitNOP(1); // end of prologue marker
}
Also used : ForwardReference(org.jikesrvm.compilers.common.assembler.ForwardReference) FloatingPointMachineRegister(org.jikesrvm.ia32.RegisterConstants.FloatingPointMachineRegister) GPR(org.jikesrvm.ia32.RegisterConstants.GPR) XMM(org.jikesrvm.ia32.RegisterConstants.XMM) TypeReference(org.jikesrvm.classloader.TypeReference) Offset(org.vmmagic.unboxed.Offset)

Example 10 with GPR

use of org.jikesrvm.ia32.RegisterConstants.GPR 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

GPR (org.jikesrvm.ia32.RegisterConstants.GPR)10 TypeReference (org.jikesrvm.classloader.TypeReference)3 ForwardReference (org.jikesrvm.compilers.common.assembler.ForwardReference)3 OptCompiledMethod (org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod)3 Offset (org.vmmagic.unboxed.Offset)3 FloatingPointMachineRegister (org.jikesrvm.ia32.RegisterConstants.FloatingPointMachineRegister)2 XMM (org.jikesrvm.ia32.RegisterConstants.XMM)2 Unpreemptible (org.vmmagic.pragma.Unpreemptible)2 Address (org.vmmagic.unboxed.Address)2 Assembler (org.jikesrvm.compilers.common.assembler.ia32.Assembler)1 IntConstantOperand (org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand)1 LongConstantOperand (org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand)1 MemoryOperand (org.jikesrvm.compilers.opt.ir.operand.MemoryOperand)1 Operand (org.jikesrvm.compilers.opt.ir.operand.Operand)1 RegisterOperand (org.jikesrvm.compilers.opt.ir.operand.RegisterOperand)1 StackLocationOperand (org.jikesrvm.compilers.opt.ir.operand.StackLocationOperand)1 TrapCodeOperand (org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand)1 IA32ConditionOperand (org.jikesrvm.compilers.opt.ir.operand.ia32.IA32ConditionOperand)1 RVMThread (org.jikesrvm.scheduler.RVMThread)1 Entrypoint (org.vmmagic.pragma.Entrypoint)1