summaryrefslogtreecommitdiff
path: root/runtime/thread.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/thread.cc')
-rw-r--r--runtime/thread.cc112
1 files changed, 59 insertions, 53 deletions
diff --git a/runtime/thread.cc b/runtime/thread.cc
index dcbe1382e0..dca08959f4 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -622,7 +622,7 @@ void* Thread::CreateCallback(void* arg) {
// while threads are being born).
CHECK(!runtime->IsShuttingDownLocked());
// Note: given that the JNIEnv is created in the parent thread, the only failure point here is
- // a mess in InitStackHwm. We do not have a reasonable way to recover from that, so abort
+ // a mess in InitStack. We do not have a reasonable way to recover from that, so abort
// the runtime in such a case. In case this ever changes, we need to make sure here to
// delete the tmp_jni_env, as we own it at this point.
CHECK(self->Init(runtime->GetThreadList(), runtime->GetJavaVM(), self->tlsPtr_.tmp_jni_env));
@@ -729,9 +729,8 @@ static size_t FixStackSize(size_t stack_size) {
return stack_size;
}
-// Return the nearest page-aligned address below the current stack top.
-NO_INLINE
-static uint8_t* FindStackTop() {
+template <>
+NO_INLINE uint8_t* Thread::FindStackTop<StackType::kHardware>() {
return reinterpret_cast<uint8_t*>(
AlignDown(__builtin_frame_address(0), gPageSize));
}
@@ -739,16 +738,17 @@ static uint8_t* FindStackTop() {
// Install a protected region in the stack. This is used to trigger a SIGSEGV if a stack
// overflow is detected. It is located right below the stack_begin_.
ATTRIBUTE_NO_SANITIZE_ADDRESS
+template <StackType stack_type>
void Thread::InstallImplicitProtection() {
- uint8_t* pregion = tlsPtr_.stack_begin - GetStackOverflowProtectedSize();
+ uint8_t* pregion = GetStackBegin<stack_type>() - GetStackOverflowProtectedSize();
// Page containing current top of stack.
- uint8_t* stack_top = FindStackTop();
+ uint8_t* stack_top = FindStackTop<stack_type>();
// Try to directly protect the stack.
VLOG(threads) << "installing stack protected region at " << std::hex <<
static_cast<void*>(pregion) << " to " <<
static_cast<void*>(pregion + GetStackOverflowProtectedSize() - 1);
- if (ProtectStack(/* fatal_on_error= */ false)) {
+ if (ProtectStack<stack_type>(/* fatal_on_error= */ false)) {
// Tell the kernel that we won't be needing these pages any more.
// NB. madvise will probably write zeroes into the memory (on linux it does).
size_t unwanted_size =
@@ -778,7 +778,7 @@ void Thread::InstallImplicitProtection() {
// (Defensively) first remove the protection on the protected region as we'll want to read
// and write it. Ignore errors.
- UnprotectStack();
+ UnprotectStack<stack_type>();
VLOG(threads) << "Need to map in stack for thread at " << std::hex <<
static_cast<void*>(pregion);
@@ -821,7 +821,7 @@ void Thread::InstallImplicitProtection() {
static_cast<void*>(pregion + GetStackOverflowProtectedSize() - 1);
// Protect the bottom of the stack to prevent read/write to it.
- ProtectStack(/* fatal_on_error= */ true);
+ ProtectStack<stack_type>(/* fatal_on_error= */ true);
// Tell the kernel that we won't be needing these pages any more.
// NB. madvise will probably write zeroes into the memory (on linux it does).
@@ -948,6 +948,11 @@ void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_siz
}
}
+static void GetThreadStack(pthread_t thread,
+ void** stack_base,
+ size_t* stack_size,
+ size_t* guard_size);
+
bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm, JNIEnvExt* jni_env_ext) {
// This function does all the initialization that must be run by the native thread it applies to.
// (When we create a new thread from managed code, we allocate the Thread* in Thread::Create so
@@ -963,7 +968,14 @@ bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm, JNIEnvExt* jni_en
ScopedTrace trace("Thread::Init");
SetUpAlternateSignalStack();
- if (!InitStackHwm()) {
+
+ void* read_stack_base = nullptr;
+ size_t read_stack_size = 0;
+ size_t read_guard_size = 0;
+ GetThreadStack(tlsPtr_.pthread_self, &read_stack_base, &read_stack_size, &read_guard_size);
+ if (!InitStack<kNativeStackType>(reinterpret_cast<uint8_t*>(read_stack_base),
+ read_stack_size,
+ read_guard_size)) {
return false;
}
InitCpu();
@@ -1331,15 +1343,12 @@ static void GetThreadStack(pthread_t thread,
#endif
}
-bool Thread::InitStackHwm() {
- ScopedTrace trace("InitStackHwm");
- void* read_stack_base;
- size_t read_stack_size;
- size_t read_guard_size;
- GetThreadStack(tlsPtr_.pthread_self, &read_stack_base, &read_stack_size, &read_guard_size);
+template <StackType stack_type>
+bool Thread::InitStack(uint8_t* read_stack_base, size_t read_stack_size, size_t read_guard_size) {
+ ScopedTrace trace("InitStack");
- tlsPtr_.stack_begin = reinterpret_cast<uint8_t*>(read_stack_base);
- tlsPtr_.stack_size = read_stack_size;
+ SetStackBegin<stack_type>(read_stack_base);
+ SetStackSize<stack_type>(read_stack_size);
// The minimum stack size we can cope with is the protected region size + stack overflow check
// region size + some memory for normal stack usage.
@@ -1372,8 +1381,16 @@ bool Thread::InitStackHwm() {
return false;
}
+ std::string stack_type_str = "";
+ if constexpr (stack_type == kNativeStackType) {
+ stack_type_str = "Native";
+ } else if constexpr (stack_type == kQuickStackType) {
+ stack_type_str = "Quick";
+ }
+
// This is included in the SIGQUIT output, but it's useful here for thread debugging.
- VLOG(threads) << StringPrintf("Native stack is at %p (%s with %s guard)",
+ VLOG(threads) << StringPrintf("%s stack is at %p (%s with %s guard)",
+ stack_type_str.c_str(),
read_stack_base,
PrettySize(read_stack_size).c_str(),
PrettySize(read_guard_size).c_str());
@@ -1384,7 +1401,7 @@ bool Thread::InitStackHwm() {
bool implicit_stack_check =
runtime->GetImplicitStackOverflowChecks() && !runtime->IsAotCompiler();
- ResetDefaultStackEnd();
+ ResetDefaultStackEnd<stack_type>();
// Install the protected region if we are doing implicit overflow checks.
if (implicit_stack_check) {
@@ -1392,15 +1409,18 @@ bool Thread::InitStackHwm() {
// to install our own region so we need to move the limits
// of the stack to make room for it.
- tlsPtr_.stack_begin += read_guard_size + GetStackOverflowProtectedSize();
- tlsPtr_.stack_end += read_guard_size + GetStackOverflowProtectedSize();
- tlsPtr_.stack_size -= read_guard_size + GetStackOverflowProtectedSize();
+ SetStackBegin<stack_type>(GetStackBegin<stack_type>() + read_guard_size
+ + GetStackOverflowProtectedSize());
+ SetStackEnd<stack_type>(GetStackEnd<stack_type>() + read_guard_size
+ + GetStackOverflowProtectedSize());
+ SetStackSize<stack_type>(GetStackSize<stack_type>() - (read_guard_size
+ + GetStackOverflowProtectedSize()));
- InstallImplicitProtection();
+ InstallImplicitProtection<stack_type>();
}
// Consistency check.
- CHECK_GT(FindStackTop(), reinterpret_cast<void*>(tlsPtr_.stack_end));
+ CHECK_GT(FindStackTop<stack_type>(), reinterpret_cast<void*>(GetStackEnd<stack_type>()));
return true;
}
@@ -2115,9 +2135,10 @@ void Thread::DumpState(std::ostream& os, const Thread* thread, pid_t tid) {
<< " core=" << task_cpu
<< " HZ=" << sysconf(_SC_CLK_TCK) << "\n";
if (thread != nullptr) {
- os << " | stack=" << reinterpret_cast<void*>(thread->tlsPtr_.stack_begin) << "-"
- << reinterpret_cast<void*>(thread->tlsPtr_.stack_end) << " stackSize="
- << PrettySize(thread->tlsPtr_.stack_size) << "\n";
+ // TODO(Simulator): Also dump the simulated stack if one exists.
+ os << " | stack=" << reinterpret_cast<void*>(thread->GetStackBegin<kNativeStackType>())
+ << "-" << reinterpret_cast<void*>(thread->GetStackEnd<kNativeStackType>())
+ << " stackSize=" << PrettySize(thread->GetStackSize<kNativeStackType>()) << "\n";
// Dump the held mutexes.
os << " | held mutexes=";
for (size_t i = 0; i < kLockLevelCount; ++i) {
@@ -2804,12 +2825,17 @@ class JniTransitionReferenceVisitor : public StackVisitor {
bool found_;
};
+bool Thread::IsRawObjOnQuickStack(uint8_t* raw_obj) const {
+ return (static_cast<size_t>(raw_obj - GetStackBegin<kQuickStackType>()) <
+ GetStackSize<kQuickStackType>());
+}
+
bool Thread::IsJniTransitionReference(jobject obj) const {
DCHECK(obj != nullptr);
// We need a non-const pointer for stack walk even if we're not modifying the thread state.
Thread* thread = const_cast<Thread*>(this);
uint8_t* raw_obj = reinterpret_cast<uint8_t*>(obj);
- if (static_cast<size_t>(raw_obj - tlsPtr_.stack_begin) < tlsPtr_.stack_size) {
+ if (IsRawObjOnQuickStack(raw_obj)) {
JniTransitionReferenceVisitor</*kPointsToStack=*/ true> visitor(thread, raw_obj);
visitor.WalkStack();
return visitor.Found();
@@ -4622,28 +4648,6 @@ void Thread::VerifyStackImpl() {
}
}
-// Set the stack end to that to be used during a stack overflow
-void Thread::SetStackEndForStackOverflow() {
- // During stack overflow we allow use of the full stack.
- if (tlsPtr_.stack_end == tlsPtr_.stack_begin) {
- // However, we seem to have already extended to use the full stack.
- LOG(ERROR) << "Need to increase kStackOverflowReservedBytes (currently "
- << GetStackOverflowReservedBytes(kRuntimeISA) << ")?";
- DumpStack(LOG_STREAM(ERROR));
- LOG(FATAL) << "Recursive stack overflow.";
- }
-
- tlsPtr_.stack_end = tlsPtr_.stack_begin;
-
- // Remove the stack overflow protection if is it set up.
- bool implicit_stack_check = Runtime::Current()->GetImplicitStackOverflowChecks();
- if (implicit_stack_check) {
- if (!UnprotectStack()) {
- LOG(ERROR) << "Unable to remove stack protection for stack overflow";
- }
- }
-}
-
void Thread::SetTlab(uint8_t* start, uint8_t* end, uint8_t* limit) {
DCHECK_LE(start, end);
DCHECK_LE(end, limit);
@@ -4691,8 +4695,9 @@ std::ostream& operator<<(std::ostream& os, const Thread& thread) {
return os;
}
+template <StackType stack_type>
bool Thread::ProtectStack(bool fatal_on_error) {
- void* pregion = tlsPtr_.stack_begin - GetStackOverflowProtectedSize();
+ void* pregion = GetStackBegin<stack_type>() - GetStackOverflowProtectedSize();
VLOG(threads) << "Protecting stack at " << pregion;
if (mprotect(pregion, GetStackOverflowProtectedSize(), PROT_NONE) == -1) {
if (fatal_on_error) {
@@ -4707,8 +4712,9 @@ bool Thread::ProtectStack(bool fatal_on_error) {
return true;
}
+template <StackType stack_type>
bool Thread::UnprotectStack() {
- void* pregion = tlsPtr_.stack_begin - GetStackOverflowProtectedSize();
+ void* pregion = GetStackBegin<stack_type>() - GetStackOverflowProtectedSize();
VLOG(threads) << "Unprotecting stack at " << pregion;
return mprotect(pregion, GetStackOverflowProtectedSize(), PROT_READ|PROT_WRITE) == 0;
}