Method prologue and epilogues, add missing x86 functionality.
Enables compiling and running a number of JNI internal managed code
methods on the host.
Change-Id: I56fceb813d0cb24637bc784ba57f2d1d16911d48
diff --git a/src/compiler/codegen/x86/ArchFactory.cc b/src/compiler/codegen/x86/ArchFactory.cc
index 1bf0a72..2d15318 100644
--- a/src/compiler/codegen/x86/ArchFactory.cc
+++ b/src/compiler/codegen/x86/ArchFactory.cc
@@ -128,18 +128,14 @@
if (cUnit->numCoreSpills == 0) {
return;
}
- UNIMPLEMENTED(WARNING) << "spillCoreRegs";
-#if 0
uint32_t mask = cUnit->coreSpillMask;
- int offset = cUnit->numCoreSpills * 4;
- opRegImm(cUnit, kOpSub, rSP, offset);
+ int offset = cUnit->frameSize - 4;
for (int reg = 0; mask; mask >>= 1, reg++) {
if (mask & 0x1) {
offset -= 4;
storeWordDisp(cUnit, rSP, offset, reg);
}
}
-#endif
}
void unSpillCoreRegs(CompilationUnit* cUnit)
@@ -147,35 +143,42 @@
if (cUnit->numCoreSpills == 0) {
return;
}
- UNIMPLEMENTED(WARNING) << "unSpillCoreRegs";
-#if 0
uint32_t mask = cUnit->coreSpillMask;
- int offset = cUnit->frameSize;
+ int offset = cUnit->frameSize - 4;
for (int reg = 0; mask; mask >>= 1, reg++) {
if (mask & 0x1) {
offset -= 4;
loadWordDisp(cUnit, rSP, offset, reg);
}
}
- opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize);
-#endif
+}
+
+void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) {
+ X86OpCode opcode = kX86Bkpt;
+ switch (op) {
+ case kOpCmp: opcode = kX86Cmp32RT; break;
+ default:
+ LOG(FATAL) << "Bad opcode: " << op;
+ break;
+ }
+ DCHECK((EncodingMap[opcode].flags & IS_BINARY_OP) != 0);
+ newLIR2(cUnit, opcode, rDest, threadOffset);
}
void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
{
- UNIMPLEMENTED(WARNING) << "genEntrySequence";
-#if 0
- int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
/*
- * On entry, rARG0, rARG1, rARG2 & rARG3 are live. Let the register
+ * On entry, rARG0, rARG1, rARG2 are live. Let the register
* allocation mechanism know so it doesn't try to use any of them when
* expanding the frame or flushing. This leaves the utility
- * code with a single temp: r12. This should be enough.
+ * code with no spare temps.
*/
oatLockTemp(cUnit, rARG0);
oatLockTemp(cUnit, rARG1);
oatLockTemp(cUnit, rARG2);
- oatLockTemp(cUnit, rARG3);
+
+ /* Build frame, return address already on stack */
+ opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - 4);
/*
* We can safely skip the stack overflow check if we're
@@ -185,63 +188,54 @@
((size_t)cUnit->frameSize <
Thread::kStackOverflowReservedBytes));
newLIR0(cUnit, kPseudoMethodEntry);
- int checkReg = oatAllocTemp(cUnit);
- int newSP = oatAllocTemp(cUnit);
- if (!skipOverflowCheck) {
- /* Load stack limit */
- loadWordDisp(cUnit, rSELF,
- Thread::StackEndOffset().Int32Value(), checkReg);
- }
/* Spill core callee saves */
spillCoreRegs(cUnit);
/* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
DCHECK_EQ(cUnit->numFPSpills, 0);
if (!skipOverflowCheck) {
- opRegRegImm(cUnit, kOpSub, newSP, rSP,
- cUnit->frameSize - (spillCount * 4));
- genRegRegCheck(cUnit, kCondCc, newSP, checkReg, NULL,
- kThrowStackOverflow);
- opRegCopy(cUnit, rSP, newSP); // Establish stack
- } else {
- opRegImm(cUnit, kOpSub, rSP,
- cUnit->frameSize - (spillCount * 4));
+ // cmp rSP, fs:[stack_end_]; jcc throw_launchpad
+ LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kThrowStackOverflow, 0, 0, 0, 0);
+ opRegThreadMem(cUnit, kOpCmp, rSP, Thread::StackEndOffset().Int32Value());
+ opCondBranch(cUnit, kCondUlt, tgt);
+ // Remember branch target - will process later
+ oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
}
+ /* Spill Method* */
storeBaseDisp(cUnit, rSP, 0, rARG0, kWord);
flushIns(cUnit);
if (cUnit->genDebugger) {
// Refresh update debugger callout
+ UNIMPLEMENTED(WARNING) << "genDebugger";
+#if 0
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
+#endif
}
oatFreeTemp(cUnit, rARG0);
oatFreeTemp(cUnit, rARG1);
oatFreeTemp(cUnit, rARG2);
- oatFreeTemp(cUnit, rARG3);
-#endif
}
-void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
-{
- UNIMPLEMENTED(WARNING) << "genExitSequence";
-#if 0
- /*
- * In the exit path, rRET0/rRET1 are live - make sure they aren't
- * allocated by the register utilities as temps.
- */
- oatLockTemp(cUnit, rRET0);
- oatLockTemp(cUnit, rRET1);
+void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb) {
+ /*
+ * In the exit path, rRET0/rRET1 are live - make sure they aren't
+ * allocated by the register utilities as temps.
+ */
+ oatLockTemp(cUnit, rRET0);
+ oatLockTemp(cUnit, rRET1);
- newLIR0(cUnit, kPseudoMethodExit);
- /* If we're compiling for the debugger, generate an update callout */
- if (cUnit->genDebugger) {
- genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
- }
- unSpillCoreRegs(cUnit);
- opReg(cUnit, kOpBx, r_RA);
-#endif
+ newLIR0(cUnit, kPseudoMethodExit);
+ /* If we're compiling for the debugger, generate an update callout */
+ if (cUnit->genDebugger) {
+ genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
+ }
+ unSpillCoreRegs(cUnit);
+ /* Remove frame except for return address */
+ opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - 4);
+ newLIR0(cUnit, kX86Ret);
}
/*
@@ -249,43 +243,39 @@
* Note: new redundant branches may be inserted later, and we'll
* use a check in final instruction assembly to nop those out.
*/
-void removeRedundantBranches(CompilationUnit* cUnit)
-{
- UNIMPLEMENTED(WARNING) << "removeRedundantBranches";
-#if 0
- LIR* thisLIR;
+void removeRedundantBranches(CompilationUnit* cUnit) {
+ LIR* thisLIR;
- for (thisLIR = (LIR*) cUnit->firstLIRInsn;
- thisLIR != (LIR*) cUnit->lastLIRInsn;
- thisLIR = NEXT_LIR(thisLIR)) {
+ for (thisLIR = (LIR*) cUnit->firstLIRInsn;
+ thisLIR != (LIR*) cUnit->lastLIRInsn;
+ thisLIR = NEXT_LIR(thisLIR)) {
- /* Branch to the next instruction */
- if (thisLIR->opcode == kX86B) {
- LIR* nextLIR = thisLIR;
+ /* Branch to the next instruction */
+ if (thisLIR->opcode == kX86Jmp) {
+ LIR* nextLIR = thisLIR;
- while (true) {
- nextLIR = NEXT_LIR(nextLIR);
+ while (true) {
+ nextLIR = NEXT_LIR(nextLIR);
- /*
- * Is the branch target the next instruction?
- */
- if (nextLIR == (LIR*) thisLIR->target) {
- thisLIR->flags.isNop = true;
- break;
- }
-
- /*
- * Found real useful stuff between the branch and the target.
- * Need to explicitly check the lastLIRInsn here because it
- * might be the last real instruction.
- */
- if (!isPseudoOpcode(nextLIR->opcode) ||
- (nextLIR = (LIR*) cUnit->lastLIRInsn))
- break;
- }
+ /*
+ * Is the branch target the next instruction?
+ */
+ if (nextLIR == (LIR*) thisLIR->target) {
+ thisLIR->flags.isNop = true;
+ break;
}
+
+ /*
+ * Found real useful stuff between the branch and the target.
+ * Need to explicitly check the lastLIRInsn here because it
+ * might be the last real instruction.
+ */
+ if (!isPseudoOpcode(nextLIR->opcode) ||
+ (nextLIR = (LIR*) cUnit->lastLIRInsn))
+ break;
+ }
}
-#endif
+ }
}