v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
v8threads.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #include "api.h"
31 #include "bootstrapper.h"
32 #include "debug.h"
33 #include "execution.h"
34 #include "v8threads.h"
35 #include "regexp-stack.h"
36 
37 namespace v8 {
38 
39 
40 // Track whether this V8 instance has ever called v8::Locker. This allows the
41 // API code to verify that the lock is always held when V8 is being entered.
42 bool Locker::active_ = false;
43 
44 
45 // Once the Locker is initialized, the current thread will be guaranteed to have
46 // the lock for a given isolate.
47 void Locker::Initialize(v8::Isolate* isolate) {
48  ASSERT(isolate != NULL);
49  has_lock_= false;
50  top_level_ = true;
51  isolate_ = reinterpret_cast<i::Isolate*>(isolate);
52  // Record that the Locker has been used at least once.
53  active_ = true;
54  // Get the big lock if necessary.
55  if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
56  isolate_->thread_manager()->Lock();
57  has_lock_ = true;
58 
59  // Make sure that V8 is initialized. Archiving of threads interferes
60  // with deserialization by adding additional root pointers, so we must
61  // initialize here, before anyone can call ~Locker() or Unlocker().
62  if (!isolate_->IsInitialized()) {
63  isolate_->Enter();
65  isolate_->Exit();
66  }
67 
68  // This may be a locker within an unlocker in which case we have to
69  // get the saved state for this thread and restore it.
70  if (isolate_->thread_manager()->RestoreThread()) {
71  top_level_ = false;
72  } else {
73  internal::ExecutionAccess access(isolate_);
74  isolate_->stack_guard()->ClearThread(access);
75  isolate_->stack_guard()->InitThread(access);
76  }
77  if (isolate_->IsDefaultIsolate()) {
78  // This only enters if not yet entered.
80  }
81  }
83 }
84 
85 
86 bool Locker::IsLocked(v8::Isolate* isolate) {
87  ASSERT(isolate != NULL);
88  i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
89  return internal_isolate->thread_manager()->IsLockedByCurrentThread();
90 }
91 
92 
94  return active_;
95 }
96 
97 
100  if (has_lock_) {
101  if (isolate_->IsDefaultIsolate()) {
102  isolate_->Exit();
103  }
104  if (top_level_) {
105  isolate_->thread_manager()->FreeThreadResources();
106  } else {
107  isolate_->thread_manager()->ArchiveThread();
108  }
109  isolate_->thread_manager()->Unlock();
110  }
111 }
112 
113 
114 void Unlocker::Initialize(v8::Isolate* isolate) {
115  ASSERT(isolate != NULL);
116  isolate_ = reinterpret_cast<i::Isolate*>(isolate);
118  if (isolate_->IsDefaultIsolate()) {
119  isolate_->Exit();
120  }
121  isolate_->thread_manager()->ArchiveThread();
122  isolate_->thread_manager()->Unlock();
123 }
124 
125 
128  isolate_->thread_manager()->Lock();
129  isolate_->thread_manager()->RestoreThread();
130  if (isolate_->IsDefaultIsolate()) {
131  isolate_->Enter();
132  }
133 }
134 
135 
136 namespace internal {
137 
138 
141  // First check whether the current thread has been 'lazily archived', i.e.
142  // not archived at all. If that is the case we put the state storage we
143  // had prepared back in the free list, since we didn't need it after all.
144  if (lazily_archived_thread_.Equals(ThreadId::Current())) {
145  lazily_archived_thread_ = ThreadId::Invalid();
146  Isolate::PerIsolateThreadData* per_thread =
147  isolate_->FindPerThreadDataForThisThread();
148  ASSERT(per_thread != NULL);
149  ASSERT(per_thread->thread_state() == lazily_archived_thread_state_);
150  lazily_archived_thread_state_->set_id(ThreadId::Invalid());
151  lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
152  lazily_archived_thread_state_ = NULL;
153  per_thread->set_thread_state(NULL);
154  return true;
155  }
156 
157  // Make sure that the preemption thread cannot modify the thread state while
158  // it is being archived or restored.
159  ExecutionAccess access(isolate_);
160 
161  // If there is another thread that was lazily archived then we have to really
162  // archive it now.
163  if (lazily_archived_thread_.IsValid()) {
164  EagerlyArchiveThread();
165  }
166  Isolate::PerIsolateThreadData* per_thread =
167  isolate_->FindPerThreadDataForThisThread();
168  if (per_thread == NULL || per_thread->thread_state() == NULL) {
169  // This is a new thread.
170  isolate_->stack_guard()->InitThread(access);
171  return false;
172  }
173  ThreadState* state = per_thread->thread_state();
174  char* from = state->data();
175  from = isolate_->handle_scope_implementer()->RestoreThread(from);
176  from = isolate_->RestoreThread(from);
177  from = Relocatable::RestoreState(isolate_, from);
178 #ifdef ENABLE_DEBUGGER_SUPPORT
179  from = isolate_->debug()->RestoreDebug(from);
180 #endif
181  from = isolate_->stack_guard()->RestoreStackGuard(from);
182  from = isolate_->regexp_stack()->RestoreStack(from);
183  from = isolate_->bootstrapper()->RestoreState(from);
184  per_thread->set_thread_state(NULL);
185  if (state->terminate_on_restore()) {
186  isolate_->stack_guard()->TerminateExecution();
187  state->set_terminate_on_restore(false);
188  }
189  state->set_id(ThreadId::Invalid());
190  state->Unlink();
192  return true;
193 }
194 
195 
197  mutex_.Lock();
198  mutex_owner_ = ThreadId::Current();
200 }
201 
202 
204  mutex_owner_ = ThreadId::Invalid();
205  mutex_.Unlock();
206 }
207 
208 
209 static int ArchiveSpacePerThread() {
212 #ifdef ENABLE_DEBUGGER_SUPPORT
213  Debug::ArchiveSpacePerThread() +
214 #endif
218  Relocatable::ArchiveSpacePerThread();
219 }
220 
221 
222 ThreadState::ThreadState(ThreadManager* thread_manager)
223  : id_(ThreadId::Invalid()),
224  terminate_on_restore_(false),
225  data_(NULL),
226  next_(this),
227  previous_(this),
228  thread_manager_(thread_manager) {
229 }
230 
231 
232 ThreadState::~ThreadState() {
233  DeleteArray<char>(data_);
234 }
235 
236 
237 void ThreadState::AllocateSpace() {
238  data_ = NewArray<char>(ArchiveSpacePerThread());
239 }
240 
241 
243  next_->previous_ = previous_;
244  previous_->next_ = next_;
245 }
246 
247 
249  ThreadState* flying_anchor =
250  list == FREE_LIST ? thread_manager_->free_anchor_
251  : thread_manager_->in_use_anchor_;
252  next_ = flying_anchor->next_;
253  previous_ = flying_anchor;
254  flying_anchor->next_ = this;
255  next_->previous_ = this;
256 }
257 
258 
260  ThreadState* gotten = free_anchor_->next_;
261  if (gotten == free_anchor_) {
262  ThreadState* new_thread_state = new ThreadState(this);
263  new_thread_state->AllocateSpace();
264  return new_thread_state;
265  }
266  return gotten;
267 }
268 
269 
270 // Gets the first in the list of archived threads.
272  return in_use_anchor_->Next();
273 }
274 
275 
277  if (next_ == thread_manager_->in_use_anchor_) return NULL;
278  return next_;
279 }
280 
281 
282 // Thread ids must start with 1, because in TLS having thread id 0 can't
283 // be distinguished from not having a thread id at all (since NULL is
284 // defined as 0.)
285 ThreadManager::ThreadManager()
286  : mutex_owner_(ThreadId::Invalid()),
287  lazily_archived_thread_(ThreadId::Invalid()),
288  lazily_archived_thread_state_(NULL),
289  free_anchor_(NULL),
290  in_use_anchor_(NULL) {
291  free_anchor_ = new ThreadState(this);
292  in_use_anchor_ = new ThreadState(this);
293 }
294 
295 
296 ThreadManager::~ThreadManager() {
297  DeleteThreadStateList(free_anchor_);
298  DeleteThreadStateList(in_use_anchor_);
299 }
300 
301 
302 void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
303  // The list starts and ends with the anchor.
304  for (ThreadState* current = anchor->next_; current != anchor;) {
305  ThreadState* next = current->next_;
306  delete current;
307  current = next;
308  }
309  delete anchor;
310 }
311 
312 
314  ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid()));
315  ASSERT(!IsArchived());
317  ThreadState* state = GetFreeThreadState();
318  state->Unlink();
319  Isolate::PerIsolateThreadData* per_thread =
320  isolate_->FindOrAllocatePerThreadDataForThisThread();
321  per_thread->set_thread_state(state);
322  lazily_archived_thread_ = ThreadId::Current();
323  lazily_archived_thread_state_ = state;
324  ASSERT(state->id().Equals(ThreadId::Invalid()));
325  state->set_id(CurrentId());
326  ASSERT(!state->id().Equals(ThreadId::Invalid()));
327 }
328 
329 
330 void ThreadManager::EagerlyArchiveThread() {
332  ThreadState* state = lazily_archived_thread_state_;
334  char* to = state->data();
335  // Ensure that data containing GC roots are archived first, and handle them
336  // in ThreadManager::Iterate(ObjectVisitor*).
337  to = isolate_->handle_scope_implementer()->ArchiveThread(to);
338  to = isolate_->ArchiveThread(to);
339  to = Relocatable::ArchiveState(isolate_, to);
340 #ifdef ENABLE_DEBUGGER_SUPPORT
341  to = isolate_->debug()->ArchiveDebug(to);
342 #endif
343  to = isolate_->stack_guard()->ArchiveStackGuard(to);
344  to = isolate_->regexp_stack()->ArchiveStack(to);
345  to = isolate_->bootstrapper()->ArchiveState(to);
346  lazily_archived_thread_ = ThreadId::Invalid();
347  lazily_archived_thread_state_ = NULL;
348 }
349 
350 
353  isolate_->FreeThreadResources();
354 #ifdef ENABLE_DEBUGGER_SUPPORT
355  isolate_->debug()->FreeThreadResources();
356 #endif
357  isolate_->stack_guard()->FreeThreadResources();
358  isolate_->regexp_stack()->FreeThreadResources();
359  isolate_->bootstrapper()->FreeThreadResources();
360 }
361 
362 
365  isolate_->FindPerThreadDataForThisThread();
366  return data != NULL && data->thread_state() != NULL;
367 }
368 
369 
370 void ThreadManager::Iterate(ObjectVisitor* v) {
371  // Expecting no threads during serialization/deserialization
372  for (ThreadState* state = FirstThreadStateInUse();
373  state != NULL;
374  state = state->Next()) {
375  char* data = state->data();
376  data = HandleScopeImplementer::Iterate(v, data);
377  data = isolate_->Iterate(v, data);
378  data = Relocatable::Iterate(v, data);
379  }
380 }
381 
382 
384  for (ThreadState* state = FirstThreadStateInUse();
385  state != NULL;
386  state = state->Next()) {
387  char* data = state->data();
389  isolate_->IterateThread(v, data);
390  }
391 }
392 
393 
395  return ThreadId::Current();
396 }
397 
398 
400  for (ThreadState* state = FirstThreadStateInUse();
401  state != NULL;
402  state = state->Next()) {
403  if (thread_id.Equals(state->id())) {
404  state->set_terminate_on_restore(true);
405  }
406  }
407 }
408 
409 
410 } // namespace internal
411 } // namespace v8
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
Definition: flags.cc:269
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
char * ArchiveState(char *to)
HandleScopeImplementer * handle_scope_implementer()
Definition: isolate.h:902
char * ArchiveThread(char *to)
Definition: api.cc:7492
void LinkInto(List list)
Definition: v8threads.cc:248
char * RestoreThread(char *from)
Definition: api.cc:7509
static int ArchiveSpacePerThread()
Definition: regexp-stack.h:86
Bootstrapper * bootstrapper()
Definition: isolate.h:858
PerIsolateThreadData * FindPerThreadDataForThisThread()
Definition: isolate.cc:165
RegExpStack * regexp_stack()
Definition: isolate.h:961
#define ASSERT(condition)
Definition: checks.h:329
char * RestoreState(char *from)
ThreadManager * thread_manager()
Definition: isolate.h:922
bool IsDefaultIsolate() const
Definition: isolate.h:501
void IterateArchivedThreads(ThreadVisitor *v)
Definition: v8threads.cc:383
StackGuard * stack_guard()
Definition: isolate.h:874
static bool IsLocked(Isolate *isolate)
Definition: v8threads.cc:86
void set_id(ThreadId id)
Definition: v8threads.h:46
void TerminateExecution(ThreadId thread_id)
Definition: v8threads.cc:399
void FreeThreadResources()
Definition: isolate.h:685
char * RestoreStackGuard(char *from)
Definition: execution.cc:629
void ClearThread(const ExecutionAccess &lock)
Definition: execution.cc:681
char * ArchiveStack(char *to)
Definition: regexp-stack.cc:57
char * ArchiveStackGuard(char *to)
Definition: execution.cc:612
static ThreadId Current()
Definition: isolate.h:170
static void EnterDefaultIsolate()
Definition: isolate.cc:229
void IterateThread(ThreadVisitor *v, char *t)
Definition: isolate.cc:259
void Iterate(ObjectVisitor *v)
Definition: isolate.cc:301
char * RestoreStack(char *from)
Definition: regexp-stack.cc:65
static bool IsActive()
Definition: v8threads.cc:93
void Iterate(ObjectVisitor *v)
Definition: v8threads.cc:370
ThreadState * GetFreeThreadState()
Definition: v8threads.cc:259
static int ArchiveSpacePerThread()
Definition: execution.h:197
void Iterate(v8::internal::ObjectVisitor *v)
Definition: api.cc:7553
static int ArchiveSpacePerThread()
Definition: isolate.h:684
char * ArchiveThread(char *to)
Definition: isolate.cc:1404
static ThreadId Invalid()
Definition: isolate.h:173
char * RestoreThread(char *from)
Definition: isolate.cc:1415
void set_terminate_on_restore(bool terminate_on_restore)
Definition: v8threads.h:51
ThreadState * FirstThreadStateInUse()
Definition: v8threads.cc:271
static int ArchiveSpacePerThread()
static bool Initialize()
Definition: api.cc:4967
void InitThread(const ExecutionAccess &lock)
Definition: execution.cc:687
ThreadState * Next()
Definition: v8threads.cc:276