use of org.jikesrvm.compilers.common.assembler.ia32.Assembler in project JikesRVM by JikesRVM.
the class JNICompiler method compile.
/**
* Compiles a method to handle the Java to C transition and back
* Transitioning from Java to C then back:
* <ol>
* <li>Set up stack frame and save non-volatile registers<li>
* <li>Set up jniEnv - set up a register to hold JNIEnv and store
* the Processor in the JNIEnv for easy access</li>
* <li>Move all native method arguments on to stack (NB at this point all
* non-volatile state is saved)</li>
* <li>Record the frame pointer of the last Java frame (this) in the jniEnv</li>
* <li>Call out to convert reference arguments to IDs</li>
* <li>Set processor as being "in native"</li>
* <li>Set up stack frame and registers for transition to C</li>
* <li>Call out to C</li>
* <li>Save result to stack</li>
* <li>Transition back from "in native" to "in Java", take care that the
* Processor isn't "blocked in native", ie other processors have decided to
* start a GC and we're not permitted to execute Java code whilst this
* occurs</li>
* <li>Convert a reference result (currently a JNI ref) into a true reference</li>
* <li>Release JNI refs</li>
* <li>Restore stack and place result in register</li>
* </ol>
*
* @param method the method to compile
* @return the compiled method (always a {@link JNICompiledMethod})
*/
public static synchronized CompiledMethod compile(NativeMethod method) {
// Meaning of constant offset into frame (assuming 4byte word size):
// Stack frame:
// on entry after prolog
//
// high address high address
// | | | | Caller frame
// | | | |
// + |arg 0 | |arg 0 | <- firstParameterOffset
// + |arg 1 | |arg 1 |
// + |... | |... |
// +8 |arg n-1 | |arg n-1 | <- lastParameterOffset
// +4 |returnAddr| |returnAddr|
// 0 + + +saved FP + <- EBP/FP value in glue frame
// -4 | | |methodID |
// -8 | | |saved EDI |
// -C | | |saved EBX |
// -10 | | |saved EBP |
// -14 | | |saved ENV | (JNIEnvironment)
// -18 | | |arg n-1 | reordered args to native method
// -1C | | | ... | ...
// -20 | | |arg 1 | ...
// -24 | | |arg 0 | ...
// -28 | | |class/obj | required second arg to native method
// -2C | | |jni funcs | required first arg to native method
// -30 | | | |
// | | | |
// | | | |
// low address low address
// Register values:
// EBP - after step 1 EBP holds a frame pointer allowing easy
// access to both this and the proceeding frame
// ESP - gradually floats down as the stack frame is initialized
// S0/ECX - reference to the JNI environment after step 3
JNICompiledMethod cm = (JNICompiledMethod) CompiledMethods.createCompiledMethod(method, CompiledMethod.JNI);
// some size for the instruction array
Assembler asm = new Assembler(100);
Address nativeIP = method.getNativeIP();
final Offset lastParameterOffset = Offset.fromIntSignExtend(2 * WORDSIZE);
// final Offset firstParameterOffset = Offset.fromIntSignExtend(WORDSIZE+(method.getParameterWords() << LG_WORDSIZE));
final TypeReference[] args = method.getParameterTypes();
// (1) Set up stack frame and save non-volatile registers
// TODO: check and resize stack once on the lowest Java to C transition
// on the stack. Not needed if we use the thread original stack
// set 2nd word of header = return address already pushed by CALL
asm.emitPUSH_RegDisp(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset());
// establish new frame
if (VM.BuildFor32Addr) {
asm.emitMOV_RegDisp_Reg(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset(), SP);
} else {
asm.emitMOV_RegDisp_Reg_Quad(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset(), SP);
}
// set first word of header: method ID
if (VM.VerifyAssertions)
VM._assert(STACKFRAME_METHOD_ID_OFFSET.toInt() == -WORDSIZE);
asm.emitPUSH_Imm(cm.getId());
// save nonvolatile registrs: EDI, EBX, EBP
if (VM.VerifyAssertions)
VM._assert(EDI_SAVE_OFFSET.toInt() == -2 * WORDSIZE);
// save nonvolatile EDI register
asm.emitPUSH_Reg(EDI);
if (VM.VerifyAssertions)
VM._assert(EBX_SAVE_OFFSET.toInt() == -3 * WORDSIZE);
// save nonvolatile EBX register
asm.emitPUSH_Reg(EBX);
if (VM.VerifyAssertions)
VM._assert(EBP_SAVE_OFFSET.toInt() == -4 * WORDSIZE);
// save nonvolatile EBP register
asm.emitPUSH_Reg(EBP);
// Establish EBP as the framepointer for use in the rest of the glue frame
if (VM.BuildFor32Addr) {
asm.emitLEA_Reg_RegDisp(EBP, SP, Offset.fromIntSignExtend(4 * WORDSIZE));
} else {
asm.emitLEA_Reg_RegDisp_Quad(EBP, SP, Offset.fromIntSignExtend(4 * WORDSIZE));
}
// S0 = RVMThread.jniEnv
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());
}
if (VM.VerifyAssertions)
VM._assert(JNI_ENV_OFFSET.toInt() == -5 * WORDSIZE);
// save JNI Env for after call
asm.emitPUSH_Reg(S0);
if (VM.VerifyAssertions)
VM._assert(BP_ON_ENTRY_OFFSET.toInt() == -6 * WORDSIZE);
asm.emitPUSH_RegDisp(S0, Entrypoints.JNIEnvBasePointerOnEntryToNative.getOffset());
// save BP into JNIEnv
if (VM.BuildFor32Addr) {
asm.emitMOV_RegDisp_Reg(S0, Entrypoints.JNIEnvBasePointerOnEntryToNative.getOffset(), EBP);
} else {
asm.emitMOV_RegDisp_Reg_Quad(S0, Entrypoints.JNIEnvBasePointerOnEntryToNative.getOffset(), EBP);
}
// (3) Move all native method arguments on to stack (NB at this
// point all non-volatile state is saved)
// (3.1) Count how many arguments could be passed in either FPRs or GPRs
int numFprArgs = 0;
int numGprArgs = 0;
for (TypeReference arg : args) {
if (arg.isFloatingPointType()) {
numFprArgs++;
} else if (VM.BuildFor32Addr && arg.isLongType()) {
numGprArgs += 2;
} else {
numGprArgs++;
}
}
// (3.2) add stack aligning padding
if (VM.BuildFor64Addr) {
int argsInRegisters = Math.min(numFprArgs, NATIVE_PARAMETER_FPRS.length) + Math.min(numGprArgs + 2, NATIVE_PARAMETER_GPRS.length);
int argsOnStack = numGprArgs + numFprArgs + 2 - argsInRegisters;
if (VM.VerifyAssertions)
VM._assert(argsOnStack >= 0);
if ((argsOnStack & 1) != 0) {
// need odd alignment prior to pushes
asm.emitAND_Reg_Imm_Quad(SP, -16);
asm.emitPUSH_Reg(T0);
} else {
// need even alignment prior to pushes
asm.emitAND_Reg_Imm_Quad(SP, -16);
}
}
// (we always pass a this or a class but we only pop this)
if (!method.isStatic()) {
numGprArgs++;
}
// (3.3) Walk over arguments backwards pushing either from memory or registers
Offset currentArg = lastParameterOffset;
int argFpr = numFprArgs - 1;
int argGpr = numGprArgs - 1;
for (int i = args.length - 1; i >= 0; i--) {
TypeReference arg = args[i];
if (arg.isFloatType()) {
if (argFpr < PARAMETER_FPRS.length) {
// make space
asm.emitPUSH_Reg(T0);
if (SSE2_FULL) {
asm.emitMOVSS_RegInd_Reg(SP, (XMM) PARAMETER_FPRS[argFpr]);
} else {
asm.emitFSTP_RegInd_Reg(SP, FP0);
}
} else {
asm.emitPUSH_RegDisp(EBP, currentArg);
}
argFpr--;
} else if (arg.isDoubleType()) {
if (VM.BuildFor32Addr) {
if (argFpr < PARAMETER_FPRS.length) {
// make space
asm.emitPUSH_Reg(T0);
// need 2 slots with 32bit addresses
asm.emitPUSH_Reg(T0);
if (SSE2_FULL) {
asm.emitMOVSD_RegInd_Reg(SP, (XMM) PARAMETER_FPRS[argFpr]);
} else {
asm.emitFSTP_RegInd_Reg_Quad(SP, FP0);
}
} else {
asm.emitPUSH_RegDisp(EBP, currentArg.plus(WORDSIZE));
// need 2 slots with 32bit addresses
asm.emitPUSH_RegDisp(EBP, currentArg);
}
} else {
if (argFpr < PARAMETER_FPRS.length) {
// make space
asm.emitPUSH_Reg(T0);
if (SSE2_FULL) {
asm.emitMOVSD_RegInd_Reg(SP, (XMM) PARAMETER_FPRS[argFpr]);
} else {
asm.emitFSTP_RegInd_Reg_Quad(SP, FP0);
}
} else {
asm.emitPUSH_RegDisp(EBP, currentArg);
}
}
argFpr--;
currentArg = currentArg.plus(WORDSIZE);
} else if (VM.BuildFor32Addr && arg.isLongType()) {
if (argGpr < PARAMETER_GPRS.length) {
asm.emitPUSH_Reg(PARAMETER_GPRS[argGpr - 1]);
asm.emitPUSH_Reg(PARAMETER_GPRS[argGpr]);
} else if (argGpr - 1 < PARAMETER_GPRS.length) {
asm.emitPUSH_Reg(PARAMETER_GPRS[argGpr - 1]);
asm.emitPUSH_RegDisp(EBP, currentArg);
} else {
asm.emitPUSH_RegDisp(EBP, currentArg.plus(WORDSIZE));
asm.emitPUSH_RegDisp(EBP, currentArg);
}
argGpr -= 2;
currentArg = currentArg.plus(WORDSIZE);
} else {
if (argGpr < PARAMETER_GPRS.length) {
asm.emitPUSH_Reg(PARAMETER_GPRS[argGpr]);
} else {
asm.emitPUSH_RegDisp(EBP, currentArg);
}
argGpr--;
if (VM.BuildFor64Addr && arg.isLongType()) {
currentArg = currentArg.plus(WORDSIZE);
}
}
currentArg = currentArg.plus(WORDSIZE);
}
// (3.4) push class or object argument
if (method.isStatic()) {
// push java.lang.Class object for klass
Offset klassOffset = Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(method.getDeclaringClass().getClassForType()));
asm.generateJTOCpush(klassOffset);
} else {
if (VM.VerifyAssertions)
VM._assert(argGpr == 0);
asm.emitPUSH_Reg(PARAMETER_GPRS[0]);
}
// (3.5) push a pointer to the JNI functions that will be
// dereferenced in native code
asm.emitPUSH_Reg(S0);
if (jniExternalFunctionsFieldOffset != 0) {
if (VM.BuildFor32Addr) {
asm.emitADD_RegInd_Imm(ESP, jniExternalFunctionsFieldOffset);
} else {
asm.emitADD_RegInd_Imm_Quad(ESP, jniExternalFunctionsFieldOffset);
}
}
// (4) Call out to convert reference arguments to IDs, set thread as
// being "in native" and record the frame pointer of the last Java frame
// (this) in the jniEnv
// Encode reference arguments into a long
int encodedReferenceOffsets = 0;
for (int i = 0, pos = 0; i < args.length; i++, pos++) {
TypeReference arg = args[i];
if (arg.isReferenceType()) {
if (VM.VerifyAssertions)
VM._assert(pos < 32);
encodedReferenceOffsets |= 1 << pos;
} else if (VM.BuildFor32Addr && (arg.isLongType() || arg.isDoubleType())) {
pos++;
}
}
// Call out to JNI environment JNI entry
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(PARAMETER_GPRS[0], EBP, JNI_ENV_OFFSET);
} else {
asm.emitMOV_Reg_RegDisp_Quad(PARAMETER_GPRS[0], EBP, JNI_ENV_OFFSET);
}
asm.emitPUSH_Reg(PARAMETER_GPRS[0]);
asm.emitMOV_Reg_Imm(PARAMETER_GPRS[1], encodedReferenceOffsets);
asm.emitPUSH_Reg(PARAMETER_GPRS[1]);
asm.baselineEmitLoadTIB(S0, PARAMETER_GPRS[0]);
asm.emitCALL_RegDisp(S0, Entrypoints.jniEntry.getOffset());
// (5) Set up stack frame and registers for transition to C
int stackholes = 0;
int position = 0;
int argsPassedInRegister = 0;
if (VM.BuildFor64Addr) {
int gpRegistersInUse = 2;
int fpRegistersInUse = 0;
boolean dataOnStack = false;
// JNI env
asm.emitPOP_Reg(NATIVE_PARAMETER_GPRS[0]);
// Object/Class
asm.emitPOP_Reg(NATIVE_PARAMETER_GPRS[1]);
argsPassedInRegister += 2;
for (TypeReference arg : method.getParameterTypes()) {
if (arg.isFloatType()) {
if (fpRegistersInUse < NATIVE_PARAMETER_FPRS.length) {
asm.emitMOVSS_Reg_RegDisp((XMM) NATIVE_PARAMETER_FPRS[fpRegistersInUse], SP, Offset.fromIntZeroExtend(position << LG_WORDSIZE));
if (dataOnStack) {
stackholes |= 1 << position;
} else {
asm.emitPOP_Reg(T0);
}
fpRegistersInUse++;
argsPassedInRegister++;
} else {
// no register available so we have data on the stack
dataOnStack = true;
}
} else if (arg.isDoubleType()) {
if (fpRegistersInUse < NATIVE_PARAMETER_FPRS.length) {
asm.emitMOVSD_Reg_RegDisp((XMM) NATIVE_PARAMETER_FPRS[fpRegistersInUse], SP, Offset.fromIntZeroExtend(position << LG_WORDSIZE));
if (dataOnStack) {
stackholes |= 1 << position;
} else {
asm.emitPOP_Reg(T0);
}
if (VM.BuildFor32Addr)
asm.emitPOP_Reg(T0);
fpRegistersInUse++;
argsPassedInRegister += VM.BuildFor32Addr ? 2 : 1;
} else {
// no register available so we have data on the stack
dataOnStack = true;
}
} else {
if (gpRegistersInUse < NATIVE_PARAMETER_GPRS.length) {
// TODO: we can't have holes in the data that is on the stack, we need to shuffle it up
asm.emitMOV_Reg_RegDisp_Quad(NATIVE_PARAMETER_GPRS[gpRegistersInUse], SP, Offset.fromIntZeroExtend(position << LG_WORDSIZE));
if (dataOnStack) {
stackholes |= 1 << position;
} else {
asm.emitPOP_Reg(T0);
}
gpRegistersInUse++;
argsPassedInRegister++;
} else {
// no register available so we have data on the stack
dataOnStack = true;
}
}
if (dataOnStack) {
position++;
}
}
position--;
int onStackOffset = position;
int mask = 0;
for (int i = position; i >= 0; i--) {
mask = 1 << i;
if ((stackholes & mask) != 0) {
continue;
}
if (i < onStackOffset) {
asm.emitMOV_Reg_RegDisp_Quad(T0, SP, Offset.fromIntZeroExtend(i << LOG_BYTES_IN_WORD));
asm.emitMOV_RegDisp_Reg_Quad(SP, Offset.fromIntZeroExtend(onStackOffset << LOG_BYTES_IN_WORD), T0);
}
onStackOffset--;
}
while (onStackOffset >= 0) {
asm.emitPOP_Reg(T0);
onStackOffset--;
}
}
// move address of native code to invoke into T0
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_Imm(T0, nativeIP.toInt());
} else {
asm.emitMOV_Reg_Imm_Quad(T0, nativeIP.toLong());
}
// Trap if stack alignment fails
if (VM.ExtremeAssertions && VM.BuildFor64Addr) {
asm.emitBT_Reg_Imm(ESP, 3);
ForwardReference fr = asm.forwardJcc(LGE);
asm.emitINT_Imm(3);
fr.resolve(asm);
}
// make the call to native code
asm.emitCALL_Reg(T0);
// (7) Discard parameters on stack
if (VM.BuildFor32Addr) {
// throw away args, class/this ptr and env
int argsToThrowAway = method.getParameterWords() + 2 - argsPassedInRegister;
if (argsToThrowAway != 0) {
asm.emitLEA_Reg_RegDisp(SP, EBP, BP_ON_ENTRY_OFFSET);
}
} else {
// throw away args, class/this ptr and env (and padding)
asm.emitLEA_Reg_RegDisp_Quad(SP, EBP, BP_ON_ENTRY_OFFSET);
}
// (8) Save result to stack
final TypeReference returnType = method.getReturnType();
if (returnType.isVoidType()) {
// Nothing to save
} else if (returnType.isFloatType()) {
// adjust stack
asm.emitPUSH_Reg(T0);
if (VM.BuildFor32Addr) {
asm.emitFSTP_RegInd_Reg(ESP, FP0);
} else {
asm.emitMOVSS_RegInd_Reg(ESP, XMM0);
}
} else if (returnType.isDoubleType()) {
// adjust stack
asm.emitPUSH_Reg(T0);
// adjust stack
asm.emitPUSH_Reg(T0);
if (VM.BuildFor32Addr) {
asm.emitFSTP_RegInd_Reg_Quad(ESP, FP0);
} else {
asm.emitMOVSD_RegInd_Reg(ESP, XMM0);
}
} else if (VM.BuildFor32Addr && returnType.isLongType()) {
asm.emitPUSH_Reg(T0);
asm.emitPUSH_Reg(T1);
} else {
// Ensure sign-extension is correct
if (returnType.isBooleanType()) {
asm.emitMOVZX_Reg_Reg_Byte(T0, T0);
} else if (returnType.isByteType()) {
asm.emitMOVSX_Reg_Reg_Byte(T0, T0);
} else if (returnType.isCharType()) {
asm.emitMOVZX_Reg_Reg_Word(T0, T0);
} else if (returnType.isShortType()) {
asm.emitMOVSX_Reg_Reg_Word(T0, T0);
}
asm.emitPUSH_Reg(T0);
}
// (9.1) reload JNIEnvironment from glue frame
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(S0, EBP, JNICompiler.JNI_ENV_OFFSET);
} else {
asm.emitMOV_Reg_RegDisp_Quad(S0, EBP, JNICompiler.JNI_ENV_OFFSET);
}
// (9.2) Reload thread register from JNIEnvironment
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(THREAD_REGISTER, S0, Entrypoints.JNIEnvSavedTRField.getOffset());
} else {
asm.emitMOV_Reg_RegDisp_Quad(THREAD_REGISTER, S0, Entrypoints.JNIEnvSavedTRField.getOffset());
}
// (9.3) Establish frame pointer to this glue method
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);
}
// result (currently a JNI ref) into a true reference, release JNI refs
if (VM.BuildFor32Addr) {
// 1st arg is JNI Env
asm.emitMOV_Reg_Reg(PARAMETER_GPRS[0], S0);
} else {
// 1st arg is JNI Env
asm.emitMOV_Reg_Reg_Quad(PARAMETER_GPRS[0], S0);
}
if (returnType.isReferenceType()) {
// 2nd arg is ref result
asm.emitPOP_Reg(PARAMETER_GPRS[1]);
} else {
// place dummy (null) operand on stack
asm.emitXOR_Reg_Reg(PARAMETER_GPRS[1], PARAMETER_GPRS[1]);
}
// save JNIEnv
asm.emitPUSH_Reg(S0);
// push arg 1
asm.emitPUSH_Reg(S0);
// push arg 2
asm.emitPUSH_Reg(PARAMETER_GPRS[1]);
// Do the call
asm.baselineEmitLoadTIB(S0, S0);
asm.emitCALL_RegDisp(S0, Entrypoints.jniExit.getOffset());
// restore JNIEnv
asm.emitPOP_Reg(S0);
// place result in register
if (returnType.isVoidType()) {
// Nothing to save
} else if (returnType.isReferenceType()) {
// value already in register
} else if (returnType.isFloatType()) {
if (SSE2_FULL) {
asm.emitMOVSS_Reg_RegInd(XMM0, ESP);
} else {
asm.emitFLD_Reg_RegInd(FP0, ESP);
}
// adjust stack
asm.emitPOP_Reg(T0);
} else if (returnType.isDoubleType()) {
if (SSE2_FULL) {
asm.emitMOVSD_Reg_RegInd(XMM0, ESP);
} else {
asm.emitFLD_Reg_RegInd_Quad(FP0, ESP);
}
// adjust stack
asm.emitPOP_Reg(T0);
// adjust stack
asm.emitPOP_Reg(T0);
} else if (VM.BuildFor32Addr && returnType.isLongType()) {
asm.emitPOP_Reg(T0);
asm.emitPOP_Reg(T1);
} else {
asm.emitPOP_Reg(T0);
}
// saved previous native BP
asm.emitPOP_Reg(EBX);
if (VM.BuildFor32Addr) {
asm.emitMOV_RegDisp_Reg(S0, Entrypoints.JNIEnvBasePointerOnEntryToNative.getOffset(), EBX);
} else {
asm.emitMOV_RegDisp_Reg_Quad(S0, Entrypoints.JNIEnvBasePointerOnEntryToNative.getOffset(), EBX);
}
// throw away JNI env
asm.emitPOP_Reg(EBX);
// restore non-volatile EBP
asm.emitPOP_Reg(EBP);
// restore non-volatile EBX
asm.emitPOP_Reg(EBX);
// restore non-volatile EDI
asm.emitPOP_Reg(EDI);
// throw away cmid
asm.emitPOP_Reg(S0);
asm.emitPOP_RegDisp(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset());
// pop parameters from stack (Note that parameterWords does not include "this")
if (method.isStatic()) {
asm.emitRET_Imm(method.getParameterWords() << LG_WORDSIZE);
} else {
asm.emitRET_Imm((method.getParameterWords() + 1) << LG_WORDSIZE);
}
CodeArray code = asm.getMachineCodes();
cm.compileComplete(code);
return cm;
}
use of org.jikesrvm.compilers.common.assembler.ia32.Assembler in project JikesRVM by JikesRVM.
the class InterfaceMethodConflictResolver method createStub.
// Create a conflict resolution stub for the set of interface method signatures l.
//
public static CodeArray createStub(int[] sigIds, RVMMethod[] targets) {
int numEntries = sigIds.length;
// (1) Create an assembler.
Assembler asm = new Assembler(numEntries);
// (2) signatures must be in ascending order (to build binary search tree).
if (VM.VerifyAssertions) {
for (int i = 1; i < sigIds.length; i++) {
VM._assert(sigIds[i - 1] < sigIds[i]);
}
}
// (3) Assign synthetic bytecode numbers to each switch such that we'll generate them
// in ascending order. This lets us use the general forward branching mechanisms
// of the Assembler.
int[] bcIndices = new int[numEntries];
assignBytecodeIndices(0, bcIndices, 0, numEntries - 1);
// (4) Generate the stub.
insertStubPrologue(asm);
insertStubCase(asm, sigIds, targets, bcIndices, 0, numEntries - 1);
return asm.getMachineCodes();
}
use of org.jikesrvm.compilers.common.assembler.ia32.Assembler in project JikesRVM by JikesRVM.
the class OutOfLineMachineCode method generateSaveThreadStateInstructions.
/**
* Machine code to implement "Magic.saveThreadState()".
* <pre>
* Registers taken at runtime:
* T0 == address of Registers object
*
* Registers returned at runtime:
* none
*
* Side effects at runtime:
* S0, T1 destroyed
* Thread state stored into Registers object
* </pre>
*
* @return instructions for saving the thread state
*/
private static CodeArray generateSaveThreadStateInstructions() {
if (VM.VerifyAssertions) {
// assuming no NV FPRs (otherwise would have to save them here)
VM._assert(NUM_NONVOLATILE_FPRS == 0);
}
Assembler asm = new Assembler(0);
Offset ipOffset = ArchEntrypoints.registersIPField.getOffset();
Offset fpOffset = ArchEntrypoints.registersFPField.getOffset();
Offset gprsOffset = ArchEntrypoints.registersGPRsField.getOffset();
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(S0, TR, ArchEntrypoints.framePointerField.getOffset());
// registers.fp := pr.framePointer
asm.emitMOV_RegDisp_Reg(T0, fpOffset, S0);
} else {
asm.emitMOV_Reg_RegDisp_Quad(S0, TR, ArchEntrypoints.framePointerField.getOffset());
// registers.fp := pr.framePointer
asm.emitMOV_RegDisp_Reg_Quad(T0, fpOffset, S0);
}
// T1 := return address (target of final jmp)
asm.emitPOP_Reg(T1);
if (VM.BuildFor32Addr) {
// registers.ip := return address
asm.emitMOV_RegDisp_Reg(T0, ipOffset, T1);
} else {
// registers.ip := return address
asm.emitMOV_RegDisp_Reg_Quad(T0, ipOffset, T1);
}
// throw away space for registers parameter (in T0)
asm.emitPOP_Reg(S0);
if (VM.BuildFor32Addr) {
// S0 := registers.gprs[]
asm.emitMOV_Reg_RegDisp(S0, T0, gprsOffset);
// registers.gprs[#SP] := SP
asm.emitMOV_RegDisp_Reg(S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE), SP);
for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) {
asm.emitMOV_RegDisp_Reg(S0, Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE), // registers.gprs[i] := i'th register
NONVOLATILE_GPRS[i]);
}
} else {
// S0 := registers.gprs[]
asm.emitMOV_Reg_RegDisp_Quad(S0, T0, gprsOffset);
// registers.gprs[#SP] := SP
asm.emitMOV_RegDisp_Reg_Quad(S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE), SP);
for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) {
asm.emitMOV_RegDisp_Reg_Quad(S0, Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE), // registers.gprs[i] := i'th register
NONVOLATILE_GPRS[i]);
}
}
// return to return address
asm.emitJMP_Reg(T1);
return asm.getMachineCodes();
}
use of org.jikesrvm.compilers.common.assembler.ia32.Assembler in project JikesRVM by JikesRVM.
the class OutOfLineMachineCode method generateThreadSwitchInstructions.
/**
* Machine code to implement "Magic.threadSwitch()".
* <pre>
* NOTE: Currently not functional for PNT: left as a guide for possible reimplementation.
*
* Parameters taken at runtime:
* T0 == address of Thread object for the current thread
* T1 == address of Registers object for the new thread
*
* Registers returned at runtime:
* none
*
* Side effects at runtime:
* sets current Thread's beingDispatched field to false
* saves current Thread's nonvolatile hardware state in its Registers object
* restores new thread's Registers nonvolatile hardware state.
* execution resumes at address specificed by restored thread's Registers ip field
* </pre>
*
* @return instructions for doing a thread switch
*/
private static CodeArray generateThreadSwitchInstructions() {
if (VM.VerifyAssertions) {
// assuming no NV FPRs (otherwise would have to save them here)
VM._assert(NUM_NONVOLATILE_FPRS == 0);
}
Assembler asm = new Assembler(0);
Offset ipOffset = ArchEntrypoints.registersIPField.getOffset();
Offset fpOffset = ArchEntrypoints.registersFPField.getOffset();
Offset gprsOffset = ArchEntrypoints.registersGPRsField.getOffset();
Offset regsOffset = Entrypoints.threadContextRegistersField.getOffset();
// (1) Save hardware state of thread we are switching off of.
if (VM.BuildFor32Addr) {
// S0 = T0.contextRegisters
asm.emitMOV_Reg_RegDisp(S0, T0, regsOffset);
} else {
// S0 = T0.contextRegisters
asm.emitMOV_Reg_RegDisp_Quad(S0, T0, regsOffset);
}
// T0.contextRegisters.ip = returnAddress
asm.emitPOP_RegDisp(S0, ipOffset);
// push TR.framePointer
asm.emitPUSH_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset());
// T0.contextRegisters.fp = pushed framepointer
asm.emitPOP_RegDisp(S0, fpOffset);
if (VM.BuildFor32Addr) {
// discard 2 words of parameters (T0, T1)
asm.emitADD_Reg_Imm(SP, 2 * WORDSIZE);
// S0 = T0.contextRegisters.gprs;
asm.emitMOV_Reg_RegDisp(S0, S0, gprsOffset);
// T0.contextRegisters.gprs[#SP] := SP
asm.emitMOV_RegDisp_Reg(S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE), SP);
for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) {
// T0.contextRegisters.gprs[i] := i'th register
asm.emitMOV_RegDisp_Reg(S0, Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE), NONVOLATILE_GPRS[i]);
}
} else {
// discard 2 words of parameters (T0, T1)
asm.emitADD_Reg_Imm_Quad(SP, 2 * WORDSIZE);
// S0 = T0.contextRegisters.gprs;
asm.emitMOV_Reg_RegDisp_Quad(S0, S0, gprsOffset);
// T0.contextRegisters.gprs[#SP] := SP
asm.emitMOV_RegDisp_Reg_Quad(S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE), SP);
for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) {
// T0.contextRegisters.gprs[i] := i'th register
asm.emitMOV_RegDisp_Reg_Quad(S0, Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE), NONVOLATILE_GPRS[i]);
}
}
// (3) Restore hardware state of thread we are switching to.
if (VM.BuildFor32Addr) {
// S0 := restoreRegs.fp
asm.emitMOV_Reg_RegDisp(S0, T1, fpOffset);
} else {
// S0 := restoreRegs.fp
asm.emitMOV_Reg_RegDisp_Quad(S0, T1, fpOffset);
}
// TR.framePointer = restoreRegs.fp
if (VM.BuildFor32Addr) {
asm.emitMOV_RegDisp_Reg(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset(), S0);
// S0 := restoreRegs.gprs[]
asm.emitMOV_Reg_RegDisp(S0, T1, gprsOffset);
// SP := restoreRegs.gprs[#SP]
asm.emitMOV_Reg_RegDisp(SP, S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE));
for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) {
// i'th register := restoreRegs.gprs[i]
asm.emitMOV_Reg_RegDisp(NONVOLATILE_GPRS[i], S0, Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE));
}
} else {
asm.emitMOV_RegDisp_Reg_Quad(THREAD_REGISTER, ArchEntrypoints.framePointerField.getOffset(), S0);
// S0 := restoreRegs.gprs[]
asm.emitMOV_Reg_RegDisp_Quad(S0, T1, gprsOffset);
// SP := restoreRegs.gprs[#SP]
asm.emitMOV_Reg_RegDisp_Quad(SP, S0, Offset.fromIntZeroExtend(SP.value() << LG_WORDSIZE));
for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) {
// i'th register := restoreRegs.gprs[i]
asm.emitMOV_Reg_RegDisp_Quad(NONVOLATILE_GPRS[i], S0, Offset.fromIntZeroExtend(NONVOLATILE_GPRS[i].value() << LG_WORDSIZE));
}
}
// return to (save) return address
asm.emitJMP_RegDisp(T1, ipOffset);
return asm.getMachineCodes();
}
use of org.jikesrvm.compilers.common.assembler.ia32.Assembler in project JikesRVM by JikesRVM.
the class CodeInstaller method install.
public static boolean install(ExecutionState state, CompiledMethod cm) {
RVMThread thread = state.getThread();
byte[] stack = thread.getStack();
Offset tsfromFPOffset = state.getTSFPOffset();
Offset fooFPOffset = state.getFPOffset();
int foomid = Magic.getIntAtOffset(stack, fooFPOffset.plus(STACKFRAME_METHOD_ID_OFFSET));
CompiledMethod foo = CompiledMethods.getCompiledMethod(foomid);
int cType = foo.getCompilerType();
// this offset is used to adjust SP to FP right after return
// from a call. 1 stack slot for return address and
// 1 stack slot for saved FP of tsfrom.
Offset sp2fpOffset = fooFPOffset.minus(tsfromFPOffset).minus(2 * BYTES_IN_STACKSLOT);
// should given an estimated length, and print the instructions
// for debugging
Assembler asm = new Assembler(50, VM.TraceOnStackReplacement);
// 1. generate bridge instructions to recover saved registers
if (cType == CompiledMethod.BASELINE) {
// unwind stack pointer, SP is FP now
if (VM.BuildFor32Addr) {
asm.emitADD_Reg_Imm(SP, sp2fpOffset.toInt());
} else {
asm.emitADD_Reg_Imm_Quad(SP, sp2fpOffset.toInt());
}
asm.generateJTOCloadWord(S0, cm.getOsrJTOCoffset());
// restore saved EDI
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(EDI, SP, EDI_SAVE_OFFSET);
} else {
asm.emitMOV_Reg_RegDisp_Quad(EDI, SP, EDI_SAVE_OFFSET);
}
// restore saved EBX
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(EBX, SP, EBX_SAVE_OFFSET);
} else {
asm.emitMOV_Reg_RegDisp_Quad(EBX, SP, EBX_SAVE_OFFSET);
}
// restore frame pointer
asm.emitPOP_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset());
// do not pop return address and parameters,
// we make a faked call to newly compiled method
asm.emitJMP_Reg(S0);
} else if (cType == CompiledMethod.OPT) {
// /////////////////////////////////////////////////
// recover saved registers from foo's stack frame
// /////////////////////////////////////////////////
OptCompiledMethod fooOpt = (OptCompiledMethod) foo;
// foo definitely not save volatile
boolean saveVolatile = fooOpt.isSaveVolatile();
if (VM.VerifyAssertions) {
VM._assert(!saveVolatile);
}
// assume SP is on foo's stack frame,
int firstNonVolatile = fooOpt.getFirstNonVolatileGPR();
int nonVolatiles = fooOpt.getNumberOfNonvolatileGPRs();
int nonVolatileOffset = fooOpt.getUnsignedNonVolatileOffset();
for (int i = firstNonVolatile; i < firstNonVolatile + nonVolatiles; i++) {
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(NONVOLATILE_GPRS[i], SP, sp2fpOffset.minus(nonVolatileOffset));
} else {
asm.emitMOV_Reg_RegDisp_Quad(NONVOLATILE_GPRS[i], SP, sp2fpOffset.minus(nonVolatileOffset));
}
nonVolatileOffset += BYTES_IN_STACKSLOT;
}
// adjust SP to frame pointer
if (VM.BuildFor32Addr) {
asm.emitADD_Reg_Imm(SP, sp2fpOffset.toInt());
} else {
asm.emitADD_Reg_Imm_Quad(SP, sp2fpOffset.toInt());
}
// restore frame pointer
asm.emitPOP_RegDisp(TR, ArchEntrypoints.framePointerField.getOffset());
// branch to the newly compiled instructions
asm.generateJTOCjmp(cm.getOsrJTOCoffset());
}
if (VM.TraceOnStackReplacement) {
VM.sysWrite("new CM instr addr ");
VM.sysWriteHex(Statics.getSlotContentsAsAddress(cm.getOsrJTOCoffset()));
VM.sysWriteln();
VM.sysWrite("JTOC register ");
VM.sysWriteHex(Magic.getTocPointer());
VM.sysWriteln();
VM.sysWrite("Thread register ");
VM.sysWriteHex(Magic.objectAsAddress(Magic.getThreadRegister()));
VM.sysWriteln();
VM.sysWriteln("tsfromFPOffset ", tsfromFPOffset);
VM.sysWriteln("fooFPOffset ", fooFPOffset);
VM.sysWriteln("SP + ", sp2fpOffset.plus(BYTES_IN_STACKSLOT));
}
// 3. set thread flags
thread.isWaitingForOsr = true;
thread.bridgeInstructions = asm.getMachineCodes();
thread.fooFPOffset = fooFPOffset;
thread.tsFPOffset = tsfromFPOffset;
Address bridgeaddr = Magic.objectAsAddress(thread.bridgeInstructions);
Memory.sync(bridgeaddr, thread.bridgeInstructions.length() << LG_INSTRUCTION_WIDTH);
AOSLogging.logger.logOsrEvent("OSR code installation succeeded");
return true;
}
Aggregations