Commit c332eb9a authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

Clean up thread initialization

This CL makes ThreadManager::InitThread *the* place that's responsible
for initializing metadata for a new thread, and ensures that all new
threads actually go through there. This was previously not the case,
and e.g. test-lockers/LockerUnlocker exposed a case where some threads
were trying to use another thread's simulator instance because the
ThreadLocalTop on the Isolate was in inconsistent state.

Change-Id: I302c643f420457f6ba73897fd45eb87969e1331c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1781688
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Auto-Submit: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63527}
parent 2b31e8aa
...@@ -2649,21 +2649,12 @@ Handle<Context> Isolate::GetIncumbentContext() { ...@@ -2649,21 +2649,12 @@ Handle<Context> Isolate::GetIncumbentContext() {
char* Isolate::ArchiveThread(char* to) { char* Isolate::ArchiveThread(char* to) {
MemCopy(to, reinterpret_cast<char*>(thread_local_top()), MemCopy(to, reinterpret_cast<char*>(thread_local_top()),
sizeof(ThreadLocalTop)); sizeof(ThreadLocalTop));
InitializeThreadLocal();
clear_pending_exception();
clear_pending_message();
clear_scheduled_exception();
return to + sizeof(ThreadLocalTop); return to + sizeof(ThreadLocalTop);
} }
char* Isolate::RestoreThread(char* from) { char* Isolate::RestoreThread(char* from) {
MemCopy(reinterpret_cast<char*>(thread_local_top()), from, MemCopy(reinterpret_cast<char*>(thread_local_top()), from,
sizeof(ThreadLocalTop)); sizeof(ThreadLocalTop));
// This might be just paranoia, but it seems to be needed in case a
// thread_local_top_ is restored on a separate OS thread.
#ifdef USE_SIMULATOR
thread_local_top()->simulator_ = Simulator::current(this);
#endif
DCHECK(context().is_null() || context().IsContext()); DCHECK(context().is_null() || context().IsContext());
return from + sizeof(ThreadLocalTop); return from + sizeof(ThreadLocalTop);
} }
...@@ -3148,7 +3139,12 @@ Isolate::~Isolate() { ...@@ -3148,7 +3139,12 @@ Isolate::~Isolate() {
default_microtask_queue_ = nullptr; default_microtask_queue_ = nullptr;
} }
void Isolate::InitializeThreadLocal() { thread_local_top()->Initialize(this); } void Isolate::InitializeThreadLocal() {
thread_local_top()->Initialize(this);
clear_pending_exception();
clear_pending_message();
clear_scheduled_exception();
}
void Isolate::SetTerminationOnExternalTryCatch() { void Isolate::SetTerminationOnExternalTryCatch() {
if (try_catch_handler() == nullptr) return; if (try_catch_handler() == nullptr) return;
......
...@@ -960,6 +960,7 @@ class Isolate final : private HiddenFactory { ...@@ -960,6 +960,7 @@ class Isolate final : private HiddenFactory {
void set_deoptimizer_lazy_throw(bool value) { void set_deoptimizer_lazy_throw(bool value) {
deoptimizer_lazy_throw_ = value; deoptimizer_lazy_throw_ = value;
} }
void InitializeThreadLocal();
ThreadLocalTop* thread_local_top() { ThreadLocalTop* thread_local_top() {
return &isolate_data_.thread_local_top_; return &isolate_data_.thread_local_top_;
} }
...@@ -1633,8 +1634,6 @@ class Isolate final : private HiddenFactory { ...@@ -1633,8 +1634,6 @@ class Isolate final : private HiddenFactory {
static void SetIsolateThreadLocals(Isolate* isolate, static void SetIsolateThreadLocals(Isolate* isolate,
PerIsolateThreadData* data); PerIsolateThreadData* data);
void InitializeThreadLocal();
void MarkCompactPrologue(bool is_compacting, void MarkCompactPrologue(bool is_compacting,
ThreadLocalTop* archived_thread_data); ThreadLocalTop* archived_thread_data);
void MarkCompactEpilogue(bool is_compacting, void MarkCompactEpilogue(bool is_compacting,
......
...@@ -194,35 +194,21 @@ void StackGuard::FreeThreadResources() { ...@@ -194,35 +194,21 @@ void StackGuard::FreeThreadResources() {
per_thread->set_stack_limit(thread_local_.real_climit_); per_thread->set_stack_limit(thread_local_.real_climit_);
} }
void StackGuard::ThreadLocal::Clear() { void StackGuard::ThreadLocal::Initialize(Isolate* isolate,
real_jslimit_ = kIllegalLimit; const ExecutionAccess& lock) {
set_jslimit(kIllegalLimit); const uintptr_t kLimitSize = FLAG_stack_size * KB;
real_climit_ = kIllegalLimit; DCHECK_GT(GetCurrentStackPosition(), kLimitSize);
set_climit(kIllegalLimit); uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
real_climit_ = limit;
set_climit(limit);
interrupt_scopes_ = nullptr; interrupt_scopes_ = nullptr;
interrupt_flags_ = 0; interrupt_flags_ = 0;
} }
void StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
if (real_climit_ == kIllegalLimit) {
const uintptr_t kLimitSize = FLAG_stack_size * KB;
DCHECK_GT(GetCurrentStackPosition(), kLimitSize);
uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
real_climit_ = limit;
set_climit(limit);
}
interrupt_scopes_ = nullptr;
interrupt_flags_ = 0;
}
void StackGuard::ClearThread(const ExecutionAccess& lock) {
thread_local_.Clear();
}
void StackGuard::InitThread(const ExecutionAccess& lock) { void StackGuard::InitThread(const ExecutionAccess& lock) {
thread_local_.Initialize(isolate_); thread_local_.Initialize(isolate_, lock);
Isolate::PerIsolateThreadData* per_thread = Isolate::PerIsolateThreadData* per_thread =
isolate_->FindOrAllocatePerThreadDataForThisThread(); isolate_->FindOrAllocatePerThreadDataForThisThread();
uintptr_t stored_limit = per_thread->stack_limit(); uintptr_t stored_limit = per_thread->stack_limit();
......
...@@ -38,12 +38,8 @@ class V8_EXPORT_PRIVATE StackGuard final { ...@@ -38,12 +38,8 @@ class V8_EXPORT_PRIVATE StackGuard final {
char* RestoreStackGuard(char* from); char* RestoreStackGuard(char* from);
static int ArchiveSpacePerThread() { return sizeof(ThreadLocal); } static int ArchiveSpacePerThread() { return sizeof(ThreadLocal); }
void FreeThreadResources(); void FreeThreadResources();
// Sets up the default stack guard for this thread if it has not // Sets up the default stack guard for this thread.
// already been set up.
void InitThread(const ExecutionAccess& lock); void InitThread(const ExecutionAccess& lock);
// Clears the stack guard for this thread so it does not look as if
// it has been set up.
void ClearThread(const ExecutionAccess& lock);
#define INTERRUPT_LIST(V) \ #define INTERRUPT_LIST(V) \
V(TERMINATE_EXECUTION, TerminateExecution, 0) \ V(TERMINATE_EXECUTION, TerminateExecution, 0) \
...@@ -127,12 +123,9 @@ class V8_EXPORT_PRIVATE StackGuard final { ...@@ -127,12 +123,9 @@ class V8_EXPORT_PRIVATE StackGuard final {
class ThreadLocal final { class ThreadLocal final {
public: public:
ThreadLocal() { Clear(); } ThreadLocal() {}
// You should hold the ExecutionAccess lock when you call Initialize or
// Clear.
void Clear();
void Initialize(Isolate* isolate); void Initialize(Isolate* isolate, const ExecutionAccess& lock);
// The stack limit is split into a JavaScript and a C++ stack limit. These // The stack limit is split into a JavaScript and a C++ stack limit. These
// two are the same except when running on a simulator where the C++ and // two are the same except when running on a simulator where the C++ and
...@@ -143,13 +136,16 @@ class V8_EXPORT_PRIVATE StackGuard final { ...@@ -143,13 +136,16 @@ class V8_EXPORT_PRIVATE StackGuard final {
// break or preemption) in which case it is lowered to make stack checks // break or preemption) in which case it is lowered to make stack checks
// fail. Both the generated code and the runtime system check against the // fail. Both the generated code and the runtime system check against the
// one without the real_ prefix. // one without the real_ prefix.
uintptr_t real_jslimit_; // Actual JavaScript stack limit set for the VM.
uintptr_t real_climit_; // Actual C++ stack limit set for the VM. // Actual JavaScript stack limit set for the VM.
uintptr_t real_jslimit_ = kIllegalLimit;
// Actual C++ stack limit set for the VM.
uintptr_t real_climit_ = kIllegalLimit;
// jslimit_ and climit_ can be read without any lock. // jslimit_ and climit_ can be read without any lock.
// Writing requires the ExecutionAccess lock. // Writing requires the ExecutionAccess lock.
base::AtomicWord jslimit_; base::AtomicWord jslimit_ = kIllegalLimit;
base::AtomicWord climit_; base::AtomicWord climit_ = kIllegalLimit;
uintptr_t jslimit() { uintptr_t jslimit() {
return bit_cast<uintptr_t>(base::Relaxed_Load(&jslimit_)); return bit_cast<uintptr_t>(base::Relaxed_Load(&jslimit_));
...@@ -166,8 +162,8 @@ class V8_EXPORT_PRIVATE StackGuard final { ...@@ -166,8 +162,8 @@ class V8_EXPORT_PRIVATE StackGuard final {
static_cast<base::AtomicWord>(limit)); static_cast<base::AtomicWord>(limit));
} }
InterruptsScope* interrupt_scopes_; InterruptsScope* interrupt_scopes_ = nullptr;
intptr_t interrupt_flags_; intptr_t interrupt_flags_ = 0;
}; };
// TODO(isolates): Technically this could be calculated directly from a // TODO(isolates): Technically this could be calculated directly from a
......
...@@ -40,10 +40,6 @@ void Locker::Initialize(v8::Isolate* isolate) { ...@@ -40,10 +40,6 @@ void Locker::Initialize(v8::Isolate* isolate) {
// get the saved state for this thread and restore it. // get the saved state for this thread and restore it.
if (isolate_->thread_manager()->RestoreThread()) { if (isolate_->thread_manager()->RestoreThread()) {
top_level_ = false; top_level_ = false;
} else {
internal::ExecutionAccess access(isolate_);
isolate_->stack_guard()->ClearThread(access);
isolate_->thread_manager()->InitThread(access);
} }
} }
DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
...@@ -88,6 +84,7 @@ Unlocker::~Unlocker() { ...@@ -88,6 +84,7 @@ Unlocker::~Unlocker() {
namespace internal { namespace internal {
void ThreadManager::InitThread(const ExecutionAccess& lock) { void ThreadManager::InitThread(const ExecutionAccess& lock) {
isolate_->InitializeThreadLocal();
isolate_->stack_guard()->InitThread(lock); isolate_->stack_guard()->InitThread(lock);
isolate_->debug()->InitThread(lock); isolate_->debug()->InitThread(lock);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment