summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/dex/quick/arm/call_arm.cc29
-rw-r--r--runtime/arch/arm/fault_handler_arm.cc135
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S25
-rw-r--r--runtime/base/logging.h1
-rw-r--r--runtime/fault_handler.cc26
-rw-r--r--runtime/parsed_options.cc3
-rw-r--r--runtime/stack.cc58
-rw-r--r--runtime/stack.h8
-rw-r--r--runtime/thread.cc15
9 files changed, 124 insertions, 176 deletions
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 163c0fe..d3477c9 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -360,6 +360,22 @@ void ArmMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
if (Runtime::Current()->ExplicitStackOverflowChecks()) {
/* Load stack limit */
Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12);
+ } else {
+ // Implicit stack overflow check.
+ // Generate a load from [sp, #-overflowsize]. If this is in the stack
+ // redzone we will get a segmentation fault.
+ //
+ // Caveat coder: if someone changes the kStackOverflowReservedBytes value
+ // we need to make sure that it's loadable in an immediate field of
+ // a sub instruction. Otherwise we will get a temp allocation and the
+ // code size will increase.
+ //
+ // This is done before the callee save instructions to avoid any possibility
+ // of these overflowing. This uses r12 and that's never saved in a callee
+ // save.
+ OpRegRegImm(kOpSub, rs_r12, rs_rARM_SP, Thread::kStackOverflowReservedBytes);
+ Load32Disp(rs_r12, 0, rs_r12);
+ MarkPossibleStackOverflowException();
}
}
/* Spill core callee saves */
@@ -418,17 +434,8 @@ void ArmMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, false, frame_size_));
}
} else {
- // Implicit stack overflow check.
- // Generate a load from [sp, #-overflowsize]. If this is in the stack
- // redzone we will get a segmentation fault.
- //
- // Caveat coder: if someone changes the kStackOverflowReservedBytes value
- // we need to make sure that it's loadable in an immediate field of
- // a sub instruction. Otherwise we will get a temp allocation and the
- // code size will increase.
- OpRegRegImm(kOpSub, rs_r12, rs_rARM_SP, Thread::kStackOverflowReservedBytes);
- Load32Disp(rs_r12, 0, rs_r12);
- MarkPossibleStackOverflowException();
+ // Implicit stack overflow check has already been done. Just make room on the
+ // stack for the frame now.
OpRegImm(kOpSub, rs_rARM_SP, frame_size_without_spills);
}
} else {
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index eddaa0b..f81e2f9 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -34,7 +34,7 @@
namespace art {
extern "C" void art_quick_throw_null_pointer_exception();
-extern "C" void art_quick_throw_stack_overflow(void*);
+extern "C" void art_quick_throw_stack_overflow_from_signal();
extern "C" void art_quick_implicit_suspend();
// Get the size of a thumb2 instruction in bytes.
@@ -50,7 +50,7 @@ void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod**
struct ucontext *uc = (struct ucontext *)context;
struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
*out_sp = static_cast<uintptr_t>(sc->arm_sp);
- LOG(DEBUG) << "sp: " << *out_sp;
+ VLOG(signals) << "sp: " << *out_sp;
if (*out_sp == 0) {
return;
}
@@ -74,7 +74,7 @@ void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod**
// Need to work out the size of the instruction that caused the exception.
uint8_t* ptr = reinterpret_cast<uint8_t*>(sc->arm_pc);
- LOG(DEBUG) << "pc: " << std::hex << static_cast<void*>(ptr);
+ VLOG(signals) << "pc: " << std::hex << static_cast<void*>(ptr);
uint32_t instr_size = GetInstructionSize(ptr);
*out_return_pc = (sc->arm_pc + instr_size) | 1;
@@ -95,7 +95,7 @@ bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
uint32_t instr_size = GetInstructionSize(ptr);
sc->arm_lr = (sc->arm_pc + instr_size) | 1; // LR needs to point to gc map location
sc->arm_pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception);
- LOG(DEBUG) << "Generating null pointer exception";
+ VLOG(signals) << "Generating null pointer exception";
return true;
}
@@ -117,10 +117,10 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
uint8_t* ptr2 = reinterpret_cast<uint8_t*>(sc->arm_pc);
uint8_t* ptr1 = ptr2 - 4;
- LOG(DEBUG) << "checking suspend";
+ VLOG(signals) << "checking suspend";
uint16_t inst2 = ptr2[0] | ptr2[1] << 8;
- LOG(DEBUG) << "inst2: " << std::hex << inst2 << " checkinst2: " << checkinst2;
+ VLOG(signals) << "inst2: " << std::hex << inst2 << " checkinst2: " << checkinst2;
if (inst2 != checkinst2) {
// Second instruction is not good, not ours.
return false;
@@ -132,7 +132,7 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
bool found = false;
while (ptr1 > limit) {
uint32_t inst1 = ((ptr1[0] | ptr1[1] << 8) << 16) | (ptr1[2] | ptr1[3] << 8);
- LOG(DEBUG) << "inst1: " << std::hex << inst1 << " checkinst1: " << checkinst1;
+ VLOG(signals) << "inst1: " << std::hex << inst1 << " checkinst1: " << checkinst1;
if (inst1 == checkinst1) {
found = true;
break;
@@ -140,7 +140,7 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
ptr1 -= 2; // Min instruction size is 2 bytes.
}
if (found) {
- LOG(DEBUG) << "suspend check match";
+ VLOG(signals) << "suspend check match";
// This is a suspend check. Arrange for the signal handler to return to
// art_quick_implicit_suspend. Also set LR so that after the suspend check it
// will resume the instruction (current PC + 2). PC points to the
@@ -148,14 +148,14 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
// NB: remember that we need to set the bottom bit of the LR register
// to switch to thumb mode.
- LOG(DEBUG) << "arm lr: " << std::hex << sc->arm_lr;
- LOG(DEBUG) << "arm pc: " << std::hex << sc->arm_pc;
+ VLOG(signals) << "arm lr: " << std::hex << sc->arm_lr;
+ VLOG(signals) << "arm pc: " << std::hex << sc->arm_pc;
sc->arm_lr = sc->arm_pc + 3; // +2 + 1 (for thumb)
sc->arm_pc = reinterpret_cast<uintptr_t>(art_quick_implicit_suspend);
// Now remove the suspend trigger that caused this fault.
Thread::Current()->RemoveSuspendTrigger();
- LOG(DEBUG) << "removed suspend trigger invoking test suspend";
+ VLOG(signals) << "removed suspend trigger invoking test suspend";
return true;
}
return false;
@@ -174,103 +174,60 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
// on the stack.
//
// If we determine this is a stack overflow we need to move the stack pointer
-// to the overflow region below the protected region. Because we now have
-// a gap in the stack (skips over protected region), we need to arrange
-// for the rest of the system to be unaware of the new stack arrangement
-// and behave as if there is a fully valid stack. We do this by placing
-// a unique address onto the stack followed by
-// the size of the gap. The stack walker will detect this and skip over the
-// gap.
-
-// NB. We also need to be careful of stack alignment as the ARM EABI specifies that
-// stack must be 8 byte aligned when making any calls.
-
-// NB. The size of the gap is the difference between the previous frame's SP and
-// the SP at which the size word is pushed.
+// to the overflow region below the protected region.
bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
struct ucontext *uc = (struct ucontext *)context;
struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
- LOG(DEBUG) << "stack overflow handler with sp at " << std::hex << &uc;
- LOG(DEBUG) << "sigcontext: " << std::hex << sc;
+ VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
+ VLOG(signals) << "sigcontext: " << std::hex << sc;
- uint8_t* sp = reinterpret_cast<uint8_t*>(sc->arm_sp);
- LOG(DEBUG) << "sp: " << static_cast<void*>(sp);
+ uintptr_t sp = sc->arm_sp;
+ VLOG(signals) << "sp: " << std::hex << sp;
- uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(sc->fault_address);
- LOG(DEBUG) << "fault_addr: " << std::hex << fault_addr;
- LOG(DEBUG) << "checking for stack overflow, sp: " << std::hex << static_cast<void*>(sp) <<
+ uintptr_t fault_addr = sc->fault_address;
+ VLOG(signals) << "fault_addr: " << std::hex << fault_addr;
+ VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
", fault_addr: " << fault_addr;
- uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>(sp - Thread::kStackOverflowReservedBytes);
+
+ uintptr_t overflow_addr = sp - Thread::kStackOverflowReservedBytes;
+
+ Thread* self = reinterpret_cast<Thread*>(sc->arm_r9);
+ CHECK_EQ(self, Thread::Current());
+ uintptr_t pregion = reinterpret_cast<uintptr_t>(self->GetStackEnd()) -
+ Thread::kStackOverflowProtectedSize;
// Check that the fault address is the value expected for a stack overflow.
if (fault_addr != overflow_addr) {
- LOG(DEBUG) << "Not a stack overflow";
+ VLOG(signals) << "Not a stack overflow";
return false;
}
// We know this is a stack overflow. We need to move the sp to the overflow region
- // the exists below the protected region. R9 contains the current Thread* so
- // we can read the stack_end from that and subtract the size of the
- // protected region. This creates a gap in the stack that needs to be marked.
- Thread* self = reinterpret_cast<Thread*>(sc->arm_r9);
+ // the exists below the protected region. Determine the address of the next
+ // available valid address below the protected region.
+ uintptr_t prevsp = sp;
+ sp = pregion;
+ VLOG(signals) << "setting sp to overflow region at " << std::hex << sp;
- uint8_t* prevsp = sp;
- sp = self->GetStackEnd() - Thread::kStackOverflowProtectedSize;
- LOG(DEBUG) << "setting sp to overflow region at " << std::hex << static_cast<void*>(sp);
-
- // We need to find the previous frame. Remember that
- // this has not yet been fully constructed because the SP has not been
- // decremented. So we need to work out the size of the spill portion of the
- // frame. This consists of something like:
- //
- // 0xb6a1d49c: e92d40e0 push {r5, r6, r7, lr}
- // 0xb6a1d4a0: ed2d8a06 vpush.f32 {s16-s21}
- //
- // The first is encoded in the ArtMethod as the spill_mask, the second as the
- // fp_spill_mask. A population count on each will give the number of registers
- // in each mask. Each register is 4 bytes on ARM32.
-
- mirror::ArtMethod* method = reinterpret_cast<mirror::ArtMethod*>(sc->arm_r0);
- uint32_t spill_mask = method->GetCoreSpillMask();
- uint32_t numcores = POPCOUNT(spill_mask);
- uint32_t fp_spill_mask = method->GetFpSpillMask();
- uint32_t numfps = POPCOUNT(fp_spill_mask);
- uint32_t spill_size = (numcores + numfps) * 4;
- LOG(DEBUG) << "spill size: " << spill_size;
- uint8_t* prevframe = prevsp + spill_size;
- LOG(DEBUG) << "previous frame: " << static_cast<void*>(prevframe);
-
- // NOTE: the ARM EABI needs an 8 byte alignment. In the case of ARM32 a pointer
- // is 4 bytes so that, together with the offset to the previous frame is 8
- // bytes. On other architectures we will need to align the stack.
-
- // Push a marker onto the stack to tell the stack walker that there is a stack
- // overflow and the stack is not contiguous.
-
- // First the offset from SP to the previous frame.
- sp -= sizeof(uint32_t);
- LOG(DEBUG) << "push gap of " << static_cast<uint32_t>(prevframe - sp);
- *reinterpret_cast<uint32_t*>(sp) = static_cast<uint32_t>(prevframe - sp);
-
- // Now the gap marker (pointer sized).
- sp -= sizeof(mirror::ArtMethod*);
- *reinterpret_cast<void**>(sp) = stack_overflow_gap_marker;
+ // Since the compiler puts the implicit overflow
+ // check before the callee save instructions, the SP is already pointing to
+ // the previous frame.
+ VLOG(signals) << "previous frame: " << std::hex << prevsp;
// Now establish the stack pointer for the signal return.
- sc->arm_sp = reinterpret_cast<uintptr_t>(sp);
+ sc->arm_sp = prevsp;
- // Now arrange for the signal handler to return to art_quick_throw_stack_overflow.
- // We need the LR to point to the GC map just after the fault instruction.
- uint8_t* ptr = reinterpret_cast<uint8_t*>(sc->arm_pc);
- uint32_t instr_size = GetInstructionSize(ptr);
- sc->arm_lr = (sc->arm_pc + instr_size) | 1; // LR needs to point to gc map location
- sc->arm_pc = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow);
+ // Tell the stack overflow code where the new stack pointer should be.
+ sc->arm_ip = sp; // aka r12
+
+ // Now arrange for the signal handler to return to art_quick_throw_stack_overflow_from_signal.
+ // The value of LR must be the same as it was when we entered the code that
+ // caused this fault. This will be inserted into a callee save frame by
+ // the function to which this handler returns (art_quick_throw_stack_overflow_from_signal).
+ sc->arm_pc = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow_from_signal);
- // The kernel will now return to the address in sc->arm_pc. We have arranged the
- // stack pointer to be in the overflow region. Throwing the exception will perform
- // a longjmp which will restore the stack pointer to the correct location for the
- // exception catch.
+ // The kernel will now return to the address in sc->arm_pc.
return true;
}
} // namespace art
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index bc80644..dcf4561 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -235,6 +235,31 @@ NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFr
*/
ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
+ /*
+ * Invoke stack overflow exception from signal handler.
+ * On entry:
+ * r9: thread
+ * sp: address of last known frame
+ * r12: address of next valid SP below protected region in stack
+ *
+ * This is deceptively simple but hides some complexity. It is called in the case of
+ * a stack overflow condition during implicit checks. The signal handler has been
+ * called by the kernel due to a load from the protected stack region. The handler
+ * works out the address of the previous frame and passes this in SP. However there
+ * is a piece of memory somewhere below the current SP that is not accessible (the
+ * memory that caused the signal). The signal handler works out the next
+ * accessible value of SP and passes this in r12. This code then sets up the SP
+ * to be this new value and calls the code to create and throw the stack overflow
+ * exception.
+ */
+ENTRY art_quick_throw_stack_overflow_from_signal
+ SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
+ mov r0, r9 @ pass Thread::Current
+ mov r1, sp @ pass SP
+ mov sp, r12 @ move SP down to below protected region.
+ b artThrowStackOverflowFromCode @ artThrowStackOverflowFromCode(Thread*, SP)
+END art_quick_throw_stack_overflow_from_signal
+
/*
* All generated callsites for interface invokes and invocation slow paths will load arguments
* as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index bd5ae85..c4461fa 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -296,6 +296,7 @@ struct LogVerbosity {
bool startup;
bool third_party_jni; // Enabled with "-verbose:third-party-jni".
bool threads;
+ bool signals;
};
extern LogVerbosity gLogVerbosity;
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index b8093bc..1304b04 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -106,23 +106,23 @@ void FaultManager::RemoveHandler(FaultHandler* handler) {
bool FaultManager::IsInGeneratedCode(void* context, bool check_dex_pc) {
// We can only be running Java code in the current thread if it
// is in Runnable state.
- LOG(DEBUG) << "Checking for generated code";
+ VLOG(signals) << "Checking for generated code";
Thread* thread = Thread::Current();
if (thread == nullptr) {
- LOG(DEBUG) << "no current thread";
+ VLOG(signals) << "no current thread";
return false;
}
ThreadState state = thread->GetState();
if (state != kRunnable) {
- LOG(DEBUG) << "not runnable";
+ VLOG(signals) << "not runnable";
return false;
}
// Current thread is runnable.
// Make sure it has the mutator lock.
if (!Locks::mutator_lock_->IsSharedHeld(thread)) {
- LOG(DEBUG) << "no lock";
+ VLOG(signals) << "no lock";
return false;
}
@@ -135,9 +135,9 @@ bool FaultManager::IsInGeneratedCode(void* context, bool check_dex_pc) {
GetMethodAndReturnPCAndSP(context, &method_obj, &return_pc, &sp);
// If we don't have a potential method, we're outta here.
- LOG(DEBUG) << "potential method: " << method_obj;
+ VLOG(signals) << "potential method: " << method_obj;
if (method_obj == 0 || !IsAligned<kObjectAlignment>(method_obj)) {
- LOG(DEBUG) << "no method";
+ VLOG(signals) << "no method";
return false;
}
@@ -147,36 +147,36 @@ bool FaultManager::IsInGeneratedCode(void* context, bool check_dex_pc) {
// TODO: Method might be not a heap address, and GetClass could fault.
mirror::Class* cls = method_obj->GetClass<kVerifyNone>();
if (cls == nullptr) {
- LOG(DEBUG) << "not a class";
+ VLOG(signals) << "not a class";
return false;
}
if (!IsAligned<kObjectAlignment>(cls)) {
- LOG(DEBUG) << "not aligned";
+ VLOG(signals) << "not aligned";
return false;
}
if (!VerifyClassClass(cls)) {
- LOG(DEBUG) << "not a class class";
+ VLOG(signals) << "not a class class";
return false;
}
// Now make sure the class is a mirror::ArtMethod.
if (!cls->IsArtMethodClass()) {
- LOG(DEBUG) << "not a method";
+ VLOG(signals) << "not a method";
return false;
}
// We can be certain that this is a method now. Check if we have a GC map
// at the return PC address.
if (true || kIsDebugBuild) {
- LOG(DEBUG) << "looking for dex pc for return pc " << std::hex << return_pc;
+ VLOG(signals) << "looking for dex pc for return pc " << std::hex << return_pc;
const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(method_obj);
uint32_t sought_offset = return_pc - reinterpret_cast<uintptr_t>(code);
- LOG(DEBUG) << "pc offset: " << std::hex << sought_offset;
+ VLOG(signals) << "pc offset: " << std::hex << sought_offset;
}
uint32_t dexpc = method_obj->ToDexPc(return_pc, false);
- LOG(DEBUG) << "dexpc: " << dexpc;
+ VLOG(signals) << "dexpc: " << dexpc;
return !check_dex_pc || dexpc != DexFile::kDexNoIndex;
}
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 9cf8785..f6a98e1 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -232,6 +232,7 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni
// gLogVerbosity.startup = true; // TODO: don't check this in!
// gLogVerbosity.third_party_jni = true; // TODO: don't check this in!
// gLogVerbosity.threads = true; // TODO: don't check this in!
+// gLogVerbosity.signals = true; // TODO: don't check this in!
method_trace_ = false;
method_trace_file_ = "/data/method-trace-file.bin";
@@ -464,6 +465,8 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni
gLogVerbosity.third_party_jni = true;
} else if (verbose_options[i] == "threads") {
gLogVerbosity.threads = true;
+ } else if (verbose_options[i] == "signals") {
+ gLogVerbosity.signals = true;
} else {
Usage("Unknown -verbose option %s\n", verbose_options[i].c_str());
return false;
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 9c709ae..5e64e59 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -32,14 +32,6 @@
namespace art {
-// Define a piece of memory, the address of which can be used as a marker
-// for the gap in the stack added during stack overflow handling.
-static uint32_t stack_overflow_object;
-
-// The stack overflow gap marker is simply a valid unique address.
-void* stack_overflow_gap_marker = &stack_overflow_object;
-
-
mirror::Object* ShadowFrame::GetThisObject() const {
mirror::ArtMethod* m = GetMethod();
if (m->IsStatic()) {
@@ -305,56 +297,23 @@ void StackVisitor::WalkStack(bool include_transitions) {
bool exit_stubs_installed = Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
uint32_t instrumentation_stack_depth = 0;
- bool kDebugStackWalk = false;
- bool kDebugStackWalkVeryVerbose = false; // The name says it all.
-
- if (kDebugStackWalk) {
- LOG(INFO) << "walking stack";
- }
for (const ManagedStack* current_fragment = thread_->GetManagedStack(); current_fragment != NULL;
current_fragment = current_fragment->GetLink()) {
cur_shadow_frame_ = current_fragment->GetTopShadowFrame();
cur_quick_frame_ = current_fragment->GetTopQuickFrame();
cur_quick_frame_pc_ = current_fragment->GetTopQuickFramePc();
- if (kDebugStackWalkVeryVerbose) {
- LOG(INFO) << "cur_quick_frame: " << cur_quick_frame_;
- LOG(INFO) << "cur_quick_frame_pc: " << std::hex << cur_quick_frame_pc_;
- }
if (cur_quick_frame_ != NULL) { // Handle quick stack frames.
// Can't be both a shadow and a quick fragment.
DCHECK(current_fragment->GetTopShadowFrame() == NULL);
mirror::ArtMethod* method = *cur_quick_frame_;
while (method != NULL) {
- // Check for a stack overflow gap marker.
- if (method == reinterpret_cast<mirror::ArtMethod*>(stack_overflow_gap_marker)) {
- // Marker for a stack overflow. This is followed by the offset from the
- // current SP to the next frame. There is a gap in the stack here. Jump
- // the gap silently.
- // Caveat coder: the layout of the overflow marker depends on the architecture.
- // The first element is address sized (8 bytes on a 64 bit machine). The second
- // element is 32 bits. So be careful with those address calculations.
-
- // Get the address of the offset, just beyond the marker pointer.
- byte* gapsizeaddr = reinterpret_cast<byte*>(cur_quick_frame_) + sizeof(uintptr_t);
- uint32_t gap = *reinterpret_cast<uint32_t*>(gapsizeaddr);
- CHECK_GT(gap, Thread::kStackOverflowProtectedSize);
- mirror::ArtMethod** next_frame = reinterpret_cast<mirror::ArtMethod**>(
- reinterpret_cast<byte*>(gapsizeaddr) + gap);
- if (kDebugStackWalk) {
- LOG(INFO) << "stack overflow marker hit, gap: " << gap << ", next_frame: " <<
- next_frame;
- }
- cur_quick_frame_ = next_frame;
- method = *next_frame;
- CHECK(method != nullptr);
- } else {
- SanityCheckFrame();
- bool should_continue = VisitFrame();
- if (UNLIKELY(!should_continue)) {
- return;
- }
+ SanityCheckFrame();
+ bool should_continue = VisitFrame();
+ if (UNLIKELY(!should_continue)) {
+ return;
}
+
if (context_ != NULL) {
context_->FillCalleeSaves(*this);
}
@@ -363,9 +322,6 @@ void StackVisitor::WalkStack(bool include_transitions) {
size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
byte* return_pc_addr = reinterpret_cast<byte*>(cur_quick_frame_) + return_pc_offset;
uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr);
- if (kDebugStackWalkVeryVerbose) {
- LOG(INFO) << "frame size: " << frame_size << ", return_pc: " << std::hex << return_pc;
- }
if (UNLIKELY(exit_stubs_installed)) {
// While profiling, the return pc is restored from the side stack, except when walking
// the stack for an exception where the side stack will be unwound in VisitFrame.
@@ -398,10 +354,6 @@ void StackVisitor::WalkStack(bool include_transitions) {
cur_quick_frame_ = reinterpret_cast<mirror::ArtMethod**>(next_frame);
cur_depth_++;
method = *cur_quick_frame_;
- if (kDebugStackWalkVeryVerbose) {
- LOG(INFO) << "new cur_quick_frame_: " << cur_quick_frame_;
- LOG(INFO) << "new cur_quick_frame_pc_: " << std::hex << cur_quick_frame_pc_;
- }
}
} else if (cur_shadow_frame_ != NULL) {
do {
diff --git a/runtime/stack.h b/runtime/stack.h
index 73a823a..88ef78f 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -102,14 +102,6 @@ enum VRegBaseRegNum : int {
kVRegNonSpecialTempBaseReg = -3,
};
-// Special object used to mark the gap in the stack placed when a stack
-// overflow fault occurs during implicit stack checking. This is not
-// a real object - it is used simply as a valid address to which a
-// mirror::ArtMethod* can be compared during a stack walk. It is inserted
-// into the stack during the stack overflow signal handling to mark the gap
-// in which the memory is protected against read and write.
-extern void* stack_overflow_gap_marker;
-
// A reference from the shadow stack to a MirrorType object within the Java heap.
template<class MirrorType>
class MANAGED StackReference : public mirror::ObjectReference<false, MirrorType> {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 23a6779..3a62cd5 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -243,10 +243,16 @@ void Thread::InstallImplicitProtection(bool is_main_stack) {
pregion -= kStackOverflowProtectedSize;
// Touch the pages in the region to map them in. Otherwise mprotect fails. Only
- // need to do this on the main stack.
+ // need to do this on the main stack. We only need to touch one byte per page.
if (is_main_stack) {
- memset(pregion, 0x55, kStackOverflowProtectedSize);
+ byte* start = pregion;
+ byte* end = pregion + kStackOverflowProtectedSize;
+ while (start < end) {
+ *start = static_cast<byte>(0);
+ start += kPageSize;
+ }
}
+
VLOG(threads) << "installing stack protected region at " << std::hex <<
static_cast<void*>(pregion) << " to " <<
static_cast<void*>(pregion + kStackOverflowProtectedSize - 1);
@@ -255,6 +261,11 @@ void Thread::InstallImplicitProtection(bool is_main_stack) {
LOG(FATAL) << "Unable to create protected region in stack for implicit overflow check. Reason:"
<< strerror(errno);
}
+
+ // Tell the kernel that we won't be needing these pages any more.
+ if (is_main_stack) {
+ madvise(pregion, kStackOverflowProtectedSize, MADV_DONTNEED);
+ }
}
void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {