// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "v8.h"
-
-#include "api.h"
-#include "bootstrapper.h"
-#include "debug.h"
-#include "execution.h"
-#include "v8threads.h"
-#include "regexp-stack.h"
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/api.h"
+#include "src/bootstrapper.h"
+#include "src/debug.h"
+#include "src/execution.h"
+#include "src/regexp-stack.h"
+#include "src/v8threads.h"
namespace v8 {
+namespace {
+
// Track whether this V8 instance has ever called v8::Locker. This allows the
// API code to verify that the lock is always held when V8 is being entered.
-bool Locker::active_ = false;
+base::Atomic32 g_locker_was_ever_used_ = 0;
+
+} // namespace
// Once the Locker is initialized, the current thread will be guaranteed to have
// the lock for a given isolate.
void Locker::Initialize(v8::Isolate* isolate) {
- ASSERT(isolate != NULL);
+ DCHECK(isolate != NULL);
has_lock_= false;
top_level_ = true;
isolate_ = reinterpret_cast<i::Isolate*>(isolate);
// Record that the Locker has been used at least once.
- active_ = true;
+ base::NoBarrier_Store(&g_locker_was_ever_used_, 1);
// Get the big lock if necessary.
if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
isolate_->thread_manager()->Lock();
has_lock_ = true;
- // Make sure that V8 is initialized. Archiving of threads interferes
- // with deserialization by adding additional root pointers, so we must
- // initialize here, before anyone can call ~Locker() or Unlocker().
- if (!isolate_->IsInitialized()) {
- isolate_->Enter();
- V8::Initialize();
- isolate_->Exit();
- }
-
// This may be a locker within an unlocker in which case we have to
// get the saved state for this thread and restore it.
if (isolate_->thread_manager()->RestoreThread()) {
isolate_->stack_guard()->ClearThread(access);
isolate_->stack_guard()->InitThread(access);
}
- if (isolate_->IsDefaultIsolate()) {
- // This only enters if not yet entered.
- internal::Isolate::EnterDefaultIsolate();
- }
}
- ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
+ DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
}
bool Locker::IsLocked(v8::Isolate* isolate) {
- ASSERT(isolate != NULL);
+ DCHECK(isolate != NULL);
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
return internal_isolate->thread_manager()->IsLockedByCurrentThread();
}
bool Locker::IsActive() {
- return active_;
+ return !!base::NoBarrier_Load(&g_locker_was_ever_used_);
}
Locker::~Locker() {
- ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
+ DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
if (has_lock_) {
- if (isolate_->IsDefaultIsolate()) {
- isolate_->Exit();
- }
if (top_level_) {
isolate_->thread_manager()->FreeThreadResources();
} else {
void Unlocker::Initialize(v8::Isolate* isolate) {
- ASSERT(isolate != NULL);
+ DCHECK(isolate != NULL);
isolate_ = reinterpret_cast<i::Isolate*>(isolate);
- ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
- if (isolate_->IsDefaultIsolate()) {
- isolate_->Exit();
- }
+ DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
isolate_->thread_manager()->ArchiveThread();
isolate_->thread_manager()->Unlock();
}
Unlocker::~Unlocker() {
- ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread());
+ DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
isolate_->thread_manager()->Lock();
isolate_->thread_manager()->RestoreThread();
- if (isolate_->IsDefaultIsolate()) {
- isolate_->Enter();
- }
-}
-
-
-void Locker::StartPreemption(v8::Isolate* isolate, int every_n_ms) {
- v8::internal::ContextSwitcher::StartPreemption(
- reinterpret_cast<i::Isolate*>(isolate), every_n_ms);
-}
-
-
-void Locker::StopPreemption(v8::Isolate* isolate) {
- v8::internal::ContextSwitcher::StopPreemption(
- reinterpret_cast<i::Isolate*>(isolate));
}
bool ThreadManager::RestoreThread() {
- ASSERT(IsLockedByCurrentThread());
+ DCHECK(IsLockedByCurrentThread());
// First check whether the current thread has been 'lazily archived', i.e.
// not archived at all. If that is the case we put the state storage we
// had prepared back in the free list, since we didn't need it after all.
lazily_archived_thread_ = ThreadId::Invalid();
Isolate::PerIsolateThreadData* per_thread =
isolate_->FindPerThreadDataForThisThread();
- ASSERT(per_thread != NULL);
- ASSERT(per_thread->thread_state() == lazily_archived_thread_state_);
+ DCHECK(per_thread != NULL);
+ DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
lazily_archived_thread_state_->set_id(ThreadId::Invalid());
lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
lazily_archived_thread_state_ = NULL;
from = isolate_->handle_scope_implementer()->RestoreThread(from);
from = isolate_->RestoreThread(from);
from = Relocatable::RestoreState(isolate_, from);
-#ifdef ENABLE_DEBUGGER_SUPPORT
from = isolate_->debug()->RestoreDebug(from);
-#endif
from = isolate_->stack_guard()->RestoreStackGuard(from);
from = isolate_->regexp_stack()->RestoreStack(from);
from = isolate_->bootstrapper()->RestoreState(from);
per_thread->set_thread_state(NULL);
if (state->terminate_on_restore()) {
- isolate_->stack_guard()->TerminateExecution();
+ isolate_->stack_guard()->RequestTerminateExecution();
state->set_terminate_on_restore(false);
}
state->set_id(ThreadId::Invalid());
void ThreadManager::Lock() {
mutex_.Lock();
mutex_owner_ = ThreadId::Current();
- ASSERT(IsLockedByCurrentThread());
+ DCHECK(IsLockedByCurrentThread());
}
static int ArchiveSpacePerThread() {
return HandleScopeImplementer::ArchiveSpacePerThread() +
Isolate::ArchiveSpacePerThread() +
-#ifdef ENABLE_DEBUGGER_SUPPORT
Debug::ArchiveSpacePerThread() +
-#endif
StackGuard::ArchiveSpacePerThread() +
RegExpStack::ArchiveSpacePerThread() +
Bootstrapper::ArchiveSpacePerThread() +
void ThreadManager::ArchiveThread() {
- ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid()));
- ASSERT(!IsArchived());
- ASSERT(IsLockedByCurrentThread());
+ DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
+ DCHECK(!IsArchived());
+ DCHECK(IsLockedByCurrentThread());
ThreadState* state = GetFreeThreadState();
state->Unlink();
Isolate::PerIsolateThreadData* per_thread =
per_thread->set_thread_state(state);
lazily_archived_thread_ = ThreadId::Current();
lazily_archived_thread_state_ = state;
- ASSERT(state->id().Equals(ThreadId::Invalid()));
+ DCHECK(state->id().Equals(ThreadId::Invalid()));
state->set_id(CurrentId());
- ASSERT(!state->id().Equals(ThreadId::Invalid()));
+ DCHECK(!state->id().Equals(ThreadId::Invalid()));
}
void ThreadManager::EagerlyArchiveThread() {
- ASSERT(IsLockedByCurrentThread());
+ DCHECK(IsLockedByCurrentThread());
ThreadState* state = lazily_archived_thread_state_;
state->LinkInto(ThreadState::IN_USE_LIST);
char* to = state->data();
to = isolate_->handle_scope_implementer()->ArchiveThread(to);
to = isolate_->ArchiveThread(to);
to = Relocatable::ArchiveState(isolate_, to);
-#ifdef ENABLE_DEBUGGER_SUPPORT
to = isolate_->debug()->ArchiveDebug(to);
-#endif
to = isolate_->stack_guard()->ArchiveStackGuard(to);
to = isolate_->regexp_stack()->ArchiveStack(to);
to = isolate_->bootstrapper()->ArchiveState(to);
void ThreadManager::FreeThreadResources() {
+ DCHECK(!isolate_->has_pending_exception());
+ DCHECK(!isolate_->external_caught_exception());
+ DCHECK(isolate_->try_catch_handler() == NULL);
isolate_->handle_scope_implementer()->FreeThreadResources();
isolate_->FreeThreadResources();
-#ifdef ENABLE_DEBUGGER_SUPPORT
isolate_->debug()->FreeThreadResources();
-#endif
isolate_->stack_guard()->FreeThreadResources();
isolate_->regexp_stack()->FreeThreadResources();
isolate_->bootstrapper()->FreeThreadResources();
}
-ContextSwitcher::ContextSwitcher(Isolate* isolate, int every_n_ms)
- : Thread("v8:CtxtSwitcher"),
- keep_going_(true),
- sleep_ms_(every_n_ms),
- isolate_(isolate) {
-}
-
-
-// Set the scheduling interval of V8 threads. This function starts the
-// ContextSwitcher thread if needed.
-void ContextSwitcher::StartPreemption(Isolate* isolate, int every_n_ms) {
- ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
- if (isolate->context_switcher() == NULL) {
- // If the ContextSwitcher thread is not running at the moment start it now.
- isolate->set_context_switcher(new ContextSwitcher(isolate, every_n_ms));
- isolate->context_switcher()->Start();
- } else {
- // ContextSwitcher thread is already running, so we just change the
- // scheduling interval.
- isolate->context_switcher()->sleep_ms_ = every_n_ms;
- }
-}
-
-
-// Disable preemption of V8 threads. If multiple threads want to use V8 they
-// must cooperatively schedule amongst them from this point on.
-void ContextSwitcher::StopPreemption(Isolate* isolate) {
- ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
- if (isolate->context_switcher() != NULL) {
- // The ContextSwitcher thread is running. We need to stop it and release
- // its resources.
- isolate->context_switcher()->keep_going_ = false;
- // Wait for the ContextSwitcher thread to exit.
- isolate->context_switcher()->Join();
- // Thread has exited, now we can delete it.
- delete(isolate->context_switcher());
- isolate->set_context_switcher(NULL);
- }
-}
-
-
-// Main loop of the ContextSwitcher thread: Preempt the currently running V8
-// thread at regular intervals.
-void ContextSwitcher::Run() {
- while (keep_going_) {
- OS::Sleep(sleep_ms_);
- isolate()->stack_guard()->Preempt();
- }
-}
-
-
-// Acknowledge the preemption by the receiving thread.
-void ContextSwitcher::PreemptionReceived() {
- // There is currently no accounting being done for this. But could be in the
- // future, which is why we leave this in.
-}
-
-
} // namespace internal
} // namespace v8