Add stack overflow check
Change-Id: I67fcb5ad4bda304879ce05561b03aa7cd46e9990
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 4ce3177..9c9bcb0 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -263,6 +263,7 @@
int frameSize;
unsigned int coreSpillMask;
unsigned int fpSpillMask;
+ unsigned int attrs;
/*
* CLEANUP/RESTRUCTURE: The code generation utilities don't have a built-in
* mechanism to propogate the original Dalvik opcode address to the
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index 4e3c9c4..cb208a5 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -1989,6 +1989,16 @@
int dfAttributes =
oatDataFlowAttributes[mir->dalvikInsn.opcode];
+ int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode);
+
+ if (flags & kInstrCanThrow) {
+ cUnit->attrs &= ~METHOD_IS_THROW_FREE;
+ }
+
+ if (flags & kInstrInvoke) {
+ cUnit->attrs &= ~METHOD_IS_LEAF;
+ }
+
int numUses = 0;
if (dfAttributes & DF_FORMAT_35C) {
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 702611d..2f86c48 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -707,6 +707,9 @@
0;
#endif
+ /* Assume non-throwing leaf */
+ cUnit.attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
+
/* Initialize the block list */
oatInitGrowableList(&cUnit.blockList, 40);
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index cf1ad04..2319a71 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -1809,14 +1809,42 @@
oatLockTemp(cUnit, r1);
oatLockTemp(cUnit, r2);
oatLockTemp(cUnit, r3);
+
+ /*
+ * We can safely skip the stack overflow check if we're
+ * a leaf *and* our frame size < fudge factor.
+ */
+ bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
+ ((size_t)cUnit->frameSize <
+ art::Thread::kStackOverflowReservedBytes));
newLIR0(cUnit, kArmPseudoMethodEntry);
+ if (!skipOverflowCheck) {
+ /* Load stack limit */
+ loadWordDisp(cUnit, rSELF,
+ art::Thread::StackEndOffset().Int32Value(), r12);
+ }
/* Spill core callee saves */
newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
/* Need to spill any FP regs? */
if (cUnit->numFPSpills) {
newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
}
- opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
+ if (!skipOverflowCheck) {
+ opRegRegImm(cUnit, kOpSub, rLR, rSP,
+ cUnit->frameSize - (cUnit->numSpills * 4));
+ opRegReg(cUnit, kOpCmp, rLR, r12); // Stack overflow?
+ /* Begin conditional skip */
+ genIT(cUnit, kArmCondCc, "TT"); // Carry clear; unsigned <
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pStackOverflowFromCode), rLR);
+ newLIR2(cUnit, kThumbAddRI8, rSP, cUnit->numSpills * 4);
+ opReg(cUnit, kOpBlx, rLR);
+ /* End conditional skip */
+ genRegCopy(cUnit, rSP, rLR); // Establish stack
+ } else {
+ opRegImm(cUnit, kOpSub, rSP,
+ cUnit->frameSize - (cUnit->numSpills * 4));
+ }
storeBaseDisp(cUnit, rSP, 0, r0, kWord);
flushIns(cUnit);
oatFreeTemp(cUnit, r0);
diff --git a/src/thread.cc b/src/thread.cc
index e1de92d..45ff6dd 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -136,6 +136,12 @@
*/
}
+// TODO: placeholder
+static void StackOverflowFromCode(Method* method) {
+ //NOTE: to save code space, this handler needs to look up its own Thread*
+ UNIMPLEMENTED(FATAL) << "Stack overflow: " << PrettyMethod(method);
+}
+
void Thread::InitFunctionPointers() {
#if defined(__arm__)
pShlLong = art_shl_long;
@@ -188,6 +194,7 @@
pUnlockObjectFromCode = UnlockObjectFromCode;
pFindFieldFromCode = Field::FindFieldFromCode;
pCheckSuspendFromCode = CheckSuspendFromCode;
+ pStackOverflowFromCode = StackOverflowFromCode;
pDebugMe = DebugMe;
}
@@ -380,7 +387,6 @@
PLOG(FATAL) << "pthread_attr_getstack failed";
}
- const size_t kStackOverflowReservedBytes = 1024; // Space to throw a StackOverflowError in.
if (stack_size <= kStackOverflowReservedBytes) {
LOG(FATAL) << "attempt to attach a thread with a too-small stack (" << stack_size << " bytes)";
}
@@ -388,7 +394,7 @@
// stack_base is the "lowest addressable byte" of the stack.
// Our stacks grow down, so we want stack_end_ to be near there, but reserving enough room
// to throw a StackOverflowError.
- stack_end_ = reinterpret_cast<byte*>(stack_base) - kStackOverflowReservedBytes;
+ stack_end_ = reinterpret_cast<byte*>(stack_base) + kStackOverflowReservedBytes;
// Sanity check.
int stack_variable;
diff --git a/src/thread.h b/src/thread.h
index 6095407..9573458 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -166,6 +166,7 @@
kTerminated,
};
+ static const size_t kStackOverflowReservedBytes = 1024; // Space to throw a StackOverflowError in.
static const size_t kDefaultStackSize = 64 * KB;
@@ -222,6 +223,7 @@
StaticStorageBase* (*pInitializeStaticStorage)(uint32_t, const Method*);
Field* (*pFindFieldFromCode)(uint32_t, const Method*);
void (*pCheckSuspendFromCode)(Thread*);
+ void (*pStackOverflowFromCode)(Method*);
class StackVisitor {
public: