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()));
}
}
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();
}
}
}
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();
}
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 -> |saved FP | |saved FP |
* | ... | | ... |
* | | | |
* |arg n-1 | |arg n-1 |
* native | ... | | ... |
* caller |arg 0 | JNIEnv* |arg 0 | JNIEnvironment
* ESP -> |return addr | |return addr |
* | | EBP -> |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 -> |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
}
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();
}
Aggregations