1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/v8threads.h"
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/api.h"
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/bootstrapper.h"
9014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/debug/debug.h"
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/execution.h"
11014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/isolate-inl.h"
12014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/regexp/regexp-stack.h"
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
17958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Berniernamespace {
18958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Track whether this V8 instance has ever called v8::Locker. This allows the
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// API code to verify that the lock is always held when V8 is being entered.
21958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierbase::Atomic32 g_locker_was_ever_used_ = 0;
22958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
23958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier}  // namespace
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Once the Locker is initialized, the current thread will be guaranteed to have
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// the lock for a given isolate.
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Locker::Initialize(v8::Isolate* isolate) {
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(isolate != NULL);
30958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  has_lock_ = false;
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  top_level_ = true;
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  isolate_ = reinterpret_cast<i::Isolate*>(isolate);
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Record that the Locker has been used at least once.
34958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  base::NoBarrier_Store(&g_locker_was_ever_used_, 1);
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the big lock if necessary.
36257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
37257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    isolate_->thread_manager()->Lock();
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    has_lock_ = true;
3944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // This may be a locker within an unlocker in which case we have to
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // get the saved state for this thread and restore it.
42257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    if (isolate_->thread_manager()->RestoreThread()) {
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      top_level_ = false;
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
45257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      internal::ExecutionAccess access(isolate_);
46257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      isolate_->stack_guard()->ClearThread(access);
47257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      isolate_->stack_guard()->InitThread(access);
48257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    }
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
54257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochbool Locker::IsLocked(v8::Isolate* isolate) {
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(isolate != NULL);
56257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
57257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  return internal_isolate->thread_manager()->IsLockedByCurrentThread();
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochbool Locker::IsActive() {
62958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  return !!base::NoBarrier_Load(&g_locker_was_ever_used_);
6369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch}
6469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
6569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockLocker::~Locker() {
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (has_lock_) {
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (top_level_) {
70257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      isolate_->thread_manager()->FreeThreadResources();
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
72257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      isolate_->thread_manager()->ArchiveThread();
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
74257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    isolate_->thread_manager()->Unlock();
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Unlocker::Initialize(v8::Isolate* isolate) {
80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(isolate != NULL);
81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  isolate_ = reinterpret_cast<i::Isolate*>(isolate);
82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
83257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  isolate_->thread_manager()->ArchiveThread();
84257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  isolate_->thread_manager()->Unlock();
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockUnlocker::~Unlocker() {
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
90257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  isolate_->thread_manager()->Lock();
91257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  isolate_->thread_manager()->RestoreThread();
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool ThreadManager::RestoreThread() {
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(IsLockedByCurrentThread());
1003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // First check whether the current thread has been 'lazily archived', i.e.
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // not archived at all.  If that is the case we put the state storage we
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // had prepared back in the free list, since we didn't need it after all.
1038b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  if (lazily_archived_thread_.Equals(ThreadId::Current())) {
1048b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    lazily_archived_thread_ = ThreadId::Invalid();
105257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    Isolate::PerIsolateThreadData* per_thread =
106257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        isolate_->FindPerThreadDataForThisThread();
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(per_thread != NULL);
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
1098b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    lazily_archived_thread_state_->set_id(ThreadId::Invalid());
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    lazily_archived_thread_state_ = NULL;
112257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    per_thread->set_thread_state(NULL);
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return true;
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Make sure that the preemption thread cannot modify the thread state while
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // it is being archived or restored.
11844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ExecutionAccess access(isolate_);
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If there is another thread that was lazily archived then we have to really
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // archive it now.
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (lazily_archived_thread_.IsValid()) {
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    EagerlyArchiveThread();
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
12544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  Isolate::PerIsolateThreadData* per_thread =
126257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      isolate_->FindPerThreadDataForThisThread();
12744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (per_thread == NULL || per_thread->thread_state() == NULL) {
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // This is a new thread.
12944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate_->stack_guard()->InitThread(access);
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return false;
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
13244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ThreadState* state = per_thread->thread_state();
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  char* from = state->data();
13444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  from = isolate_->handle_scope_implementer()->RestoreThread(from);
13544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  from = isolate_->RestoreThread(from);
136257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  from = Relocatable::RestoreState(isolate_, from);
13744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  from = isolate_->debug()->RestoreDebug(from);
13844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  from = isolate_->stack_guard()->RestoreStackGuard(from);
13944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  from = isolate_->regexp_stack()->RestoreStack(from);
14044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  from = isolate_->bootstrapper()->RestoreState(from);
14144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  per_thread->set_thread_state(NULL);
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (state->terminate_on_restore()) {
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    isolate_->stack_guard()->RequestTerminateExecution();
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    state->set_terminate_on_restore(false);
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1468b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  state->set_id(ThreadId::Invalid());
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  state->Unlink();
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  state->LinkInto(ThreadState::FREE_LIST);
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadManager::Lock() {
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  mutex_.Lock();
1558b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  mutex_owner_ = ThreadId::Current();
156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(IsLockedByCurrentThread());
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadManager::Unlock() {
1618b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  mutex_owner_ = ThreadId::Invalid();
162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  mutex_.Unlock();
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic int ArchiveSpacePerThread() {
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return HandleScopeImplementer::ArchiveSpacePerThread() +
16844f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        Isolate::ArchiveSpacePerThread() +
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          Debug::ArchiveSpacePerThread() +
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                     StackGuard::ArchiveSpacePerThread() +
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                    RegExpStack::ArchiveSpacePerThread() +
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                   Bootstrapper::ArchiveSpacePerThread() +
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                    Relocatable::ArchiveSpacePerThread();
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
17744f0eee88ff00398ff7f715fab053374d808c90dSteve BlockThreadState::ThreadState(ThreadManager* thread_manager)
1788b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    : id_(ThreadId::Invalid()),
17944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      terminate_on_restore_(false),
180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      data_(NULL),
18144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      next_(this),
18244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      previous_(this),
18344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      thread_manager_(thread_manager) {
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochThreadState::~ThreadState() {
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DeleteArray<char>(data_);
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadState::AllocateSpace() {
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  data_ = NewArray<char>(ArchiveSpacePerThread());
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadState::Unlink() {
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  next_->previous_ = previous_;
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  previous_->next_ = next_;
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadState::LinkInto(List list) {
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ThreadState* flying_anchor =
20544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      list == FREE_LIST ? thread_manager_->free_anchor_
20644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                        : thread_manager_->in_use_anchor_;
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  next_ = flying_anchor->next_;
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  previous_ = flying_anchor;
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  flying_anchor->next_ = this;
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  next_->previous_ = this;
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
21444f0eee88ff00398ff7f715fab053374d808c90dSteve BlockThreadState* ThreadManager::GetFreeThreadState() {
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ThreadState* gotten = free_anchor_->next_;
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (gotten == free_anchor_) {
21744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    ThreadState* new_thread_state = new ThreadState(this);
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    new_thread_state->AllocateSpace();
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return new_thread_state;
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return gotten;
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Gets the first in the list of archived threads.
22644f0eee88ff00398ff7f715fab053374d808c90dSteve BlockThreadState* ThreadManager::FirstThreadStateInUse() {
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return in_use_anchor_->Next();
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockThreadState* ThreadState::Next() {
23244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  if (next_ == thread_manager_->in_use_anchor_) return NULL;
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return next_;
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Thread ids must start with 1, because in TLS having thread id 0 can't
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// be distinguished from not having a thread id at all (since NULL is
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// defined as 0.)
24044f0eee88ff00398ff7f715fab053374d808c90dSteve BlockThreadManager::ThreadManager()
241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    : mutex_owner_(ThreadId::Invalid()),
2428b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch      lazily_archived_thread_(ThreadId::Invalid()),
24344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      lazily_archived_thread_state_(NULL),
24444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      free_anchor_(NULL),
24544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      in_use_anchor_(NULL) {
24644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  free_anchor_ = new ThreadState(this);
24744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  in_use_anchor_ = new ThreadState(this);
24844f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
24944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
25044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
25144f0eee88ff00398ff7f715fab053374d808c90dSteve BlockThreadManager::~ThreadManager() {
252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DeleteThreadStateList(free_anchor_);
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DeleteThreadStateList(in_use_anchor_);
254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // The list starts and ends with the anchor.
259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (ThreadState* current = anchor->next_; current != anchor;) {
260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ThreadState* next = current->next_;
261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    delete current;
262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    current = next;
263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  delete anchor;
26544f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadManager::ArchiveThread() {
269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(!IsArchived());
271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(IsLockedByCurrentThread());
27244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  ThreadState* state = GetFreeThreadState();
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  state->Unlink();
274257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Isolate::PerIsolateThreadData* per_thread =
275257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      isolate_->FindOrAllocatePerThreadDataForThisThread();
276257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  per_thread->set_thread_state(state);
2778b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  lazily_archived_thread_ = ThreadId::Current();
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lazily_archived_thread_state_ = state;
279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(state->id().Equals(ThreadId::Invalid()));
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  state->set_id(CurrentId());
281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(!state->id().Equals(ThreadId::Invalid()));
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadManager::EagerlyArchiveThread() {
286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(IsLockedByCurrentThread());
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ThreadState* state = lazily_archived_thread_state_;
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  state->LinkInto(ThreadState::IN_USE_LIST);
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  char* to = state->data();
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Ensure that data containing GC roots are archived first, and handle them
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // in ThreadManager::Iterate(ObjectVisitor*).
29244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  to = isolate_->handle_scope_implementer()->ArchiveThread(to);
29344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  to = isolate_->ArchiveThread(to);
294257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  to = Relocatable::ArchiveState(isolate_, to);
29544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  to = isolate_->debug()->ArchiveDebug(to);
29644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  to = isolate_->stack_guard()->ArchiveStackGuard(to);
29744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  to = isolate_->regexp_stack()->ArchiveStack(to);
29844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  to = isolate_->bootstrapper()->ArchiveState(to);
2998b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  lazily_archived_thread_ = ThreadId::Invalid();
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  lazily_archived_thread_state_ = NULL;
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadManager::FreeThreadResources() {
305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(!isolate_->has_pending_exception());
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(!isolate_->external_caught_exception());
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(isolate_->try_catch_handler() == NULL);
30844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  isolate_->handle_scope_implementer()->FreeThreadResources();
30944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  isolate_->FreeThreadResources();
31044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  isolate_->debug()->FreeThreadResources();
31144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  isolate_->stack_guard()->FreeThreadResources();
31244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  isolate_->regexp_stack()->FreeThreadResources();
31344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  isolate_->bootstrapper()->FreeThreadResources();
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool ThreadManager::IsArchived() {
318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  Isolate::PerIsolateThreadData* data =
319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      isolate_->FindPerThreadDataForThisThread();
32044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return data != NULL && data->thread_state() != NULL;
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid ThreadManager::Iterate(ObjectVisitor* v) {
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Expecting no threads during serialization/deserialization
32644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  for (ThreadState* state = FirstThreadStateInUse();
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       state != NULL;
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       state = state->Next()) {
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    char* data = state->data();
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    data = HandleScopeImplementer::Iterate(v, data);
33144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    data = isolate_->Iterate(v, data);
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    data = Relocatable::Iterate(v, data);
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3377f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
33844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  for (ThreadState* state = FirstThreadStateInUse();
3396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block       state != NULL;
3406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block       state = state->Next()) {
3416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    char* data = state->data();
3426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    data += HandleScopeImplementer::ArchiveSpacePerThread();
34344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    isolate_->IterateThread(v, data);
3446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
3456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
3466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3488b112d2025046f85ef7f6be087c6129c872ebad2Ben MurdochThreadId ThreadManager::CurrentId() {
3498b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch  return ThreadId::Current();
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3538b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdochvoid ThreadManager::TerminateExecution(ThreadId thread_id) {
35444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  for (ThreadState* state = FirstThreadStateInUse();
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       state != NULL;
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block       state = state->Next()) {
3578b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch    if (thread_id.Equals(state->id())) {
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      state->set_terminate_on_restore(true);
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}  // namespace internal
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}  // namespace v8
366