From 7088aea3ebbf0f0ce0ca904b248b5f751b3def6e Mon Sep 17 00:00:00 2001 From: "dslomov@chromium.org" Date: Fri, 29 Apr 2011 22:16:45 +0000 Subject: [PATCH] Revert "This implements per-isolate locking and unlocking, including tests" This reverts commit 76c78febb70e75b18214f5fe45de95c7fb515386. This change has broken test-thread-termination/TerminateMultipleV8Threads TBR=vitalyr Review URL: http://codereview.chromium.org/6903154 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7735 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8.h | 59 ++-- src/api.cc | 9 +- src/api.h | 6 +- src/execution.cc | 5 +- src/isolate.cc | 26 +- src/isolate.h | 10 +- src/objects.cc | 6 +- src/objects.h | 4 +- src/top.cc | 4 +- src/v8threads.cc | 118 ++++--- test/cctest/SConscript | 1 - test/cctest/cctest.gyp | 1 - test/cctest/test-api.cc | 23 -- test/cctest/test-lockers.cc | 605 ------------------------------------ 14 files changed, 105 insertions(+), 772 deletions(-) delete mode 100644 test/cctest/test-lockers.cc diff --git a/include/v8.h b/include/v8.h index 98d0b5dba4..b621f0110a 100644 --- a/include/v8.h +++ b/include/v8.h @@ -3355,20 +3355,26 @@ class V8EXPORT Context { * to the user of V8 to ensure (perhaps with locking) that this * constraint is not violated. * - * v8::Locker is a scoped lock object. While it's - * active (i.e. between its construction and destruction) the current thread is - * allowed to use the locked isolate. V8 guarantees that an isolate can be locked - * by at most one thread at any time. In other words, the scope of a v8::Locker is - * a critical section. + * More then one thread and multiple V8 isolates can be used + * without any locking if each isolate is created and accessed + * by a single thread only. For example, one thread can use + * multiple isolates or multiple threads can each create and run + * their own isolate. * - * Sample usage: -* \code + * If you wish to start using V8 isolate in more then one thread + * you can do this by constructing a v8::Locker object to guard + * access to the isolate. After the code using V8 has completed + * for the current thread you can call the destructor. This can + * be combined with C++ scope-based construction as follows + * (assumes the default isolate that is used if not specified as + * a parameter for the Locker): + * + * \code * ... * { - * v8::Locker locker(isolate); - * v8::Isolate::Scope isolate_scope(isolate); + * v8::Locker locker; * ... - * // Code using V8 and isolate goes here. + * // Code using V8 goes here. * ... * } // Destructor called here * \endcode @@ -3379,13 +3385,11 @@ class V8EXPORT Context { * * \code * { - * isolate->Exit(); - * v8::Unlocker unlocker(isolate); + * v8::Unlocker unlocker; * ... * // Code not using V8 goes here while V8 can run in another thread. * ... * } // Destructor called here. - * isolate->Enter(); * \endcode * * The Unlocker object is intended for use in a long-running callback @@ -3405,45 +3409,32 @@ class V8EXPORT Context { * \code * // V8 not locked. * { - * v8::Locker locker(isolate); - * Isolate::Scope isolate_scope(isolate); + * v8::Locker locker; * // V8 locked. * { - * v8::Locker another_locker(isolate); + * v8::Locker another_locker; * // V8 still locked (2 levels). * { - * isolate->Exit(); - * v8::Unlocker unlocker(isolate); + * v8::Unlocker unlocker; * // V8 not locked. * } - * isolate->Enter(); * // V8 locked again (2 levels). * } * // V8 still locked (1 level). * } * // V8 Now no longer locked. * \endcode - * - * */ class V8EXPORT Unlocker { public: - /** - * Initialize Unlocker for a given Isolate. NULL means default isolate. - */ - explicit Unlocker(Isolate* isolate = NULL); + Unlocker(); ~Unlocker(); - private: - internal::Isolate* isolate_; }; class V8EXPORT Locker { public: - /** - * Initialize Locker for a given Isolate. NULL means default isolate. - */ - explicit Locker(Isolate* isolate = NULL); + Locker(); ~Locker(); /** @@ -3461,10 +3452,9 @@ class V8EXPORT Locker { static void StopPreemption(); /** - * Returns whether or not the locker for a given isolate, or default isolate if NULL is given, - * is locked by the current thread. + * Returns whether or not the locker is locked by the current thread. */ - static bool IsLocked(Isolate* isolate = NULL); + static bool IsLocked(); /** * Returns whether v8::Locker is being used by this V8 instance. @@ -3474,7 +3464,6 @@ class V8EXPORT Locker { private: bool has_lock_; bool top_level_; - internal::Isolate* isolate_; static bool active_; diff --git a/src/api.cc b/src/api.cc index 0ec27fe423..84c0be46c9 100644 --- a/src/api.cc +++ b/src/api.cc @@ -53,6 +53,7 @@ #define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr)) +// TODO(isolates): avoid repeated TLS reads in function prologues. #ifdef ENABLE_VMSTATE_TRACKING #define ENTER_V8(isolate) \ ASSERT((isolate)->IsInitialized()); \ @@ -289,7 +290,6 @@ static inline bool EnsureInitializedForIsolate(i::Isolate* isolate, if (isolate != NULL) { if (isolate->IsInitialized()) return true; } - ASSERT(isolate == i::Isolate::Current()); return ApiCheck(InitializeHelper(), location, "Error initializing V8"); } @@ -5687,8 +5687,9 @@ void HandleScopeImplementer::FreeThreadResources() { char* HandleScopeImplementer::ArchiveThread(char* storage) { + Isolate* isolate = Isolate::Current(); v8::ImplementationUtilities::HandleScopeData* current = - isolate_->handle_scope_data(); + isolate->handle_scope_data(); handle_scope_data_ = *current; memcpy(storage, this, sizeof(*this)); @@ -5706,7 +5707,7 @@ int HandleScopeImplementer::ArchiveSpacePerThread() { char* HandleScopeImplementer::RestoreThread(char* storage) { memcpy(this, storage, sizeof(*this)); - *isolate_->handle_scope_data() = handle_scope_data_; + *Isolate::Current()->handle_scope_data() = handle_scope_data_; return storage + ArchiveSpacePerThread(); } @@ -5732,7 +5733,7 @@ void HandleScopeImplementer::IterateThis(ObjectVisitor* v) { void HandleScopeImplementer::Iterate(ObjectVisitor* v) { v8::ImplementationUtilities::HandleScopeData* current = - isolate_->handle_scope_data(); + Isolate::Current()->handle_scope_data(); handle_scope_data_ = *current; IterateThis(v); } diff --git a/src/api.h b/src/api.h index 6ea2df906a..7423d28e2f 100644 --- a/src/api.h +++ b/src/api.h @@ -399,9 +399,8 @@ class StringTracker { ISOLATED_CLASS HandleScopeImplementer { public: - explicit HandleScopeImplementer(Isolate* isolate) - : isolate_(isolate), - blocks_(0), + HandleScopeImplementer() + : blocks_(0), entered_contexts_(0), saved_contexts_(0), spare_(NULL), @@ -467,7 +466,6 @@ ISOLATED_CLASS HandleScopeImplementer { ASSERT(call_depth_ == 0); } - Isolate* isolate_; List blocks_; // Used as a stack to keep track of entered contexts. List > entered_contexts_; diff --git a/src/execution.cc b/src/execution.cc index d511b90158..eb26438fe8 100644 --- a/src/execution.cc +++ b/src/execution.cc @@ -457,9 +457,8 @@ void StackGuard::ClearThread(const ExecutionAccess& lock) { void StackGuard::InitThread(const ExecutionAccess& lock) { if (thread_local_.Initialize()) isolate_->heap()->SetStackLimits(); - Isolate::PerIsolateThreadData* per_thread = - isolate_->FindOrAllocatePerThreadDataForThisThread(); - uintptr_t stored_limit = per_thread->stack_limit(); + uintptr_t stored_limit = + Isolate::CurrentPerIsolateThreadData()->stack_limit(); // You should hold the ExecutionAccess lock when you call this. if (stored_limit != 0) { StackGuard::SetStackLimit(stored_limit); diff --git a/src/isolate.cc b/src/isolate.cc index 0b0f0bf582..6fc671c50c 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -311,17 +311,6 @@ Isolate::PerIsolateThreadData* } -Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThisThread() { - ThreadId thread_id = ThreadId::Current(); - PerIsolateThreadData* per_thread = NULL; - { - ScopedLock lock(process_wide_mutex_); - per_thread = thread_data_table_->Lookup(this, thread_id); - } - return per_thread; -} - - void Isolate::EnsureDefaultIsolate() { ScopedLock lock(process_wide_mutex_); if (default_isolate_ == NULL) { @@ -333,9 +322,7 @@ void Isolate::EnsureDefaultIsolate() { } // Can't use SetIsolateThreadLocals(default_isolate_, NULL) here // becase a non-null thread data may be already set. - if (Thread::GetThreadLocal(isolate_key_) == NULL) { - Thread::SetThreadLocal(isolate_key_, default_isolate_); - } + Thread::SetThreadLocal(isolate_key_, default_isolate_); CHECK(default_isolate_->PreInit()); } @@ -471,11 +458,6 @@ Isolate::Isolate() zone_.isolate_ = this; stack_guard_.isolate_ = this; - // ThreadManager is initialized early to support locking an isolate - // before it is entered. - thread_manager_ = new ThreadManager(); - thread_manager_->isolate_ = this; - #if defined(V8_TARGET_ARCH_ARM) && !defined(__arm__) || \ defined(V8_TARGET_ARCH_MIPS) && !defined(__mips__) simulator_initialized_ = false; @@ -661,6 +643,7 @@ bool Isolate::PreInit() { TRACE_ISOLATE(preinit); ASSERT(Isolate::Current() == this); + #ifdef ENABLE_DEBUGGER_SUPPORT debug_ = new Debug(this); debugger_ = new Debugger(); @@ -688,6 +671,8 @@ bool Isolate::PreInit() { string_tracker_ = new StringTracker(); string_tracker_->isolate_ = this; + thread_manager_ = new ThreadManager(); + thread_manager_->isolate_ = this; compilation_cache_ = new CompilationCache(this); transcendental_cache_ = new TranscendentalCache(); keyed_lookup_cache_ = new KeyedLookupCache(); @@ -698,7 +683,7 @@ bool Isolate::PreInit() { write_input_buffer_ = new StringInputBuffer(); global_handles_ = new GlobalHandles(this); bootstrapper_ = new Bootstrapper(); - handle_scope_implementer_ = new HandleScopeImplementer(this); + handle_scope_implementer_ = new HandleScopeImplementer(); stub_cache_ = new StubCache(this); ast_sentinels_ = new AstSentinels(); regexp_stack_ = new RegExpStack(); @@ -715,7 +700,6 @@ bool Isolate::PreInit() { void Isolate::InitializeThreadLocal() { - thread_local_top_.isolate_ = this; thread_local_top_.Initialize(); clear_pending_exception(); clear_pending_message(); diff --git a/src/isolate.h b/src/isolate.h index af3a99a89f..52c7145e2c 100644 --- a/src/isolate.h +++ b/src/isolate.h @@ -224,7 +224,6 @@ class ThreadLocalTop BASE_EMBEDDED { ASSERT(try_catch_handler_address_ == NULL); } - Isolate* isolate_; // The context where the current execution method is created and for variable // lookups. Context* context_; @@ -487,10 +486,6 @@ class Isolate { // Safe to call multiple times. static void EnsureDefaultIsolate(); - // Find the PerThread for this particular (isolate, thread) combination - // If one does not yet exist, return null. - PerIsolateThreadData* FindPerThreadDataForThisThread(); - #ifdef ENABLE_DEBUGGER_SUPPORT // Get the debugger from the default isolate. Preinitializes the // default isolate if needed. @@ -1070,7 +1065,7 @@ class Isolate { // If one does not yet exist, allocate a new one. PerIsolateThreadData* FindOrAllocatePerThreadDataForThisThread(); -// PreInits and returns a default isolate. Needed when a new thread tries + // PreInits and returns a default isolate. Needed when a new thread tries // to create a Locker for the first time (the lock itself is in the isolate). static Isolate* GetDefaultIsolateForLocking(); @@ -1202,12 +1197,9 @@ class Isolate { friend class ExecutionAccess; friend class IsolateInitializer; - friend class ThreadManager; - friend class StackGuard; friend class ThreadId; friend class v8::Isolate; friend class v8::Locker; - friend class v8::Unlocker; DISALLOW_COPY_AND_ASSIGN(Isolate); }; diff --git a/src/objects.cc b/src/objects.cc index b41b34c4a4..7c2097fa30 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -4958,7 +4958,8 @@ int Relocatable::ArchiveSpacePerThread() { // Archive statics that are thread local. -char* Relocatable::ArchiveState(Isolate* isolate, char* to) { +char* Relocatable::ArchiveState(char* to) { + Isolate* isolate = Isolate::Current(); *reinterpret_cast(to) = isolate->relocatable_top(); isolate->set_relocatable_top(NULL); return to + ArchiveSpacePerThread(); @@ -4966,7 +4967,8 @@ char* Relocatable::ArchiveState(Isolate* isolate, char* to) { // Restore statics that are thread local. -char* Relocatable::RestoreState(Isolate* isolate, char* from) { +char* Relocatable::RestoreState(char* from) { + Isolate* isolate = Isolate::Current(); isolate->set_relocatable_top(*reinterpret_cast(from)); return from + ArchiveSpacePerThread(); } diff --git a/src/objects.h b/src/objects.h index 1e62ce0110..556aaa2b75 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5924,8 +5924,8 @@ class Relocatable BASE_EMBEDDED { static void PostGarbageCollectionProcessing(); static int ArchiveSpacePerThread(); - static char* ArchiveState(Isolate* isolate, char* to); - static char* RestoreState(Isolate* isolate, char* from); + static char* ArchiveState(char* to); + static char* RestoreState(char* from); static void Iterate(ObjectVisitor* v); static void Iterate(ObjectVisitor* v, Relocatable* top); static char* Iterate(ObjectVisitor* v, char* t); diff --git a/src/top.cc b/src/top.cc index 6d68231351..f44de7ad68 100644 --- a/src/top.cc +++ b/src/top.cc @@ -77,9 +77,9 @@ void ThreadLocalTop::Initialize() { InitializeInternal(); #ifdef USE_SIMULATOR #ifdef V8_TARGET_ARCH_ARM - simulator_ = Simulator::current(isolate_); + simulator_ = Simulator::current(Isolate::Current()); #elif V8_TARGET_ARCH_MIPS - simulator_ = Simulator::current(isolate_); + simulator_ = Simulator::current(Isolate::Current()); #endif #endif thread_id_ = ThreadId::Current(); diff --git a/src/v8threads.cc b/src/v8threads.cc index e287974802..4b033fcf0b 100644 --- a/src/v8threads.cc +++ b/src/v8threads.cc @@ -43,85 +43,90 @@ bool Locker::active_ = false; // Constructor for the Locker object. Once the Locker is constructed the -// current thread will be guaranteed to have the lock for a given isolate. -Locker::Locker(v8::Isolate* isolate) - : has_lock_(false), - top_level_(false), - isolate_(reinterpret_cast(isolate)) { - if (isolate_ == NULL) { - isolate_ = i::Isolate::GetDefaultIsolateForLocking(); - } +// current thread will be guaranteed to have the big V8 lock. +Locker::Locker() : has_lock_(false), top_level_(true) { + // TODO(isolates): When Locker has Isolate parameter and it is provided, grab + // that one instead of using the current one. + // We pull default isolate for Locker constructor w/o p[arameter. + // A thread should not enter an isolate before acquiring a lock, + // in cases which mandate using Lockers. + // So getting a lock is the first thing threads do in a scenario where + // multple threads share an isolate. Hence, we need to access + // 'locking isolate' before we can actually enter into default isolate. + internal::Isolate* isolate = internal::Isolate::GetDefaultIsolateForLocking(); + ASSERT(isolate != NULL); + // Record that the Locker has been used at least once. active_ = true; // Get the big lock if necessary. - if (!isolate_->thread_manager()->IsLockedByCurrentThread()) { - isolate_->thread_manager()->Lock(); + if (!isolate->thread_manager()->IsLockedByCurrentThread()) { + isolate->thread_manager()->Lock(); has_lock_ = true; + if (isolate->IsDefaultIsolate()) { + // This only enters if not yet entered. + internal::Isolate::EnterDefaultIsolate(); + } + + ASSERT(internal::Thread::HasThreadLocal( + internal::Isolate::thread_id_key())); + // 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_->IsDefaultIsolate()) { - // This only enters if not yet entered. - internal::Isolate::EnterDefaultIsolate(); - } else if (!isolate_->IsInitialized()) { - isolate_->Enter(); + if (!isolate->IsInitialized()) { 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()) { + if (isolate->thread_manager()->RestoreThread()) { top_level_ = false; } else { - internal::ExecutionAccess access(isolate_); - isolate_->stack_guard()->ClearThread(access); - isolate_->stack_guard()->InitThread(access); + internal::ExecutionAccess access(isolate); + isolate->stack_guard()->ClearThread(access); + isolate->stack_guard()->InitThread(access); } } - ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); + ASSERT(isolate->thread_manager()->IsLockedByCurrentThread()); } -bool Locker::IsLocked(v8::Isolate* isolate) { - i::Isolate* internal_isolate = reinterpret_cast(isolate); - if (internal_isolate == NULL) { - internal_isolate = i::Isolate::GetDefaultIsolateForLocking(); - } - return internal_isolate->thread_manager()->IsLockedByCurrentThread(); +bool Locker::IsLocked() { + return internal::Isolate::Current()->thread_manager()-> + IsLockedByCurrentThread(); } Locker::~Locker() { - ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); + // TODO(isolate): this should use a field storing the isolate it + // locked instead. + internal::Isolate* isolate = internal::Isolate::Current(); + ASSERT(isolate->thread_manager()->IsLockedByCurrentThread()); if (has_lock_) { if (top_level_) { - isolate_->thread_manager()->FreeThreadResources(); + isolate->thread_manager()->FreeThreadResources(); } else { - isolate_->thread_manager()->ArchiveThread(); + isolate->thread_manager()->ArchiveThread(); } - isolate_->thread_manager()->Unlock(); + isolate->thread_manager()->Unlock(); } } -Unlocker::Unlocker(v8::Isolate* isolate) - : isolate_(reinterpret_cast(isolate)) { - if (isolate_ == NULL) { - isolate_ = i::Isolate::GetDefaultIsolateForLocking(); - } - - ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread()); - isolate_->thread_manager()->ArchiveThread(); - isolate_->thread_manager()->Unlock(); +Unlocker::Unlocker() { + internal::Isolate* isolate = internal::Isolate::Current(); + ASSERT(isolate->thread_manager()->IsLockedByCurrentThread()); + isolate->thread_manager()->ArchiveThread(); + isolate->thread_manager()->Unlock(); } Unlocker::~Unlocker() { - ASSERT(!isolate_->thread_manager()->IsLockedByCurrentThread()); - isolate_->thread_manager()->Lock(); - isolate_->thread_manager()->RestoreThread(); + // TODO(isolates): check it's the isolate we unlocked. + internal::Isolate* isolate = internal::Isolate::Current(); + ASSERT(!isolate->thread_manager()->IsLockedByCurrentThread()); + isolate->thread_manager()->Lock(); + isolate->thread_manager()->RestoreThread(); } @@ -139,20 +144,17 @@ namespace internal { bool ThreadManager::RestoreThread() { - ASSERT(IsLockedByCurrentThread()); // First check whether the current thread has been 'lazily archived', ie // 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. if (lazily_archived_thread_.Equals(ThreadId::Current())) { lazily_archived_thread_ = ThreadId::Invalid(); - Isolate::PerIsolateThreadData* per_thread = - isolate_->FindPerThreadDataForThisThread(); - ASSERT(per_thread != NULL); - ASSERT(per_thread->thread_state() == lazily_archived_thread_state_); + ASSERT(Isolate::CurrentPerIsolateThreadData()->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; - per_thread->set_thread_state(NULL); + Isolate::CurrentPerIsolateThreadData()->set_thread_state(NULL); return true; } @@ -166,7 +168,7 @@ bool ThreadManager::RestoreThread() { EagerlyArchiveThread(); } Isolate::PerIsolateThreadData* per_thread = - isolate_->FindPerThreadDataForThisThread(); + Isolate::CurrentPerIsolateThreadData(); if (per_thread == NULL || per_thread->thread_state() == NULL) { // This is a new thread. isolate_->stack_guard()->InitThread(access); @@ -176,7 +178,7 @@ bool ThreadManager::RestoreThread() { char* from = state->data(); from = isolate_->handle_scope_implementer()->RestoreThread(from); from = isolate_->RestoreThread(from); - from = Relocatable::RestoreState(isolate_, from); + from = Relocatable::RestoreState(from); #ifdef ENABLE_DEBUGGER_SUPPORT from = isolate_->debug()->RestoreDebug(from); #endif @@ -298,12 +300,9 @@ ThreadManager::~ThreadManager() { void ThreadManager::ArchiveThread() { ASSERT(lazily_archived_thread_.Equals(ThreadId::Invalid())); ASSERT(!IsArchived()); - ASSERT(IsLockedByCurrentThread()); ThreadState* state = GetFreeThreadState(); state->Unlink(); - Isolate::PerIsolateThreadData* per_thread = - isolate_->FindOrAllocatePerThreadDataForThisThread(); - per_thread->set_thread_state(state); + Isolate::CurrentPerIsolateThreadData()->set_thread_state(state); lazily_archived_thread_ = ThreadId::Current(); lazily_archived_thread_state_ = state; ASSERT(state->id().Equals(ThreadId::Invalid())); @@ -313,7 +312,6 @@ void ThreadManager::ArchiveThread() { void ThreadManager::EagerlyArchiveThread() { - ASSERT(IsLockedByCurrentThread()); ThreadState* state = lazily_archived_thread_state_; state->LinkInto(ThreadState::IN_USE_LIST); char* to = state->data(); @@ -321,7 +319,7 @@ void ThreadManager::EagerlyArchiveThread() { // in ThreadManager::Iterate(ObjectVisitor*). to = isolate_->handle_scope_implementer()->ArchiveThread(to); to = isolate_->ArchiveThread(to); - to = Relocatable::ArchiveState(isolate_, to); + to = Relocatable::ArchiveState(to); #ifdef ENABLE_DEBUGGER_SUPPORT to = isolate_->debug()->ArchiveDebug(to); #endif @@ -346,11 +344,11 @@ void ThreadManager::FreeThreadResources() { bool ThreadManager::IsArchived() { - Isolate::PerIsolateThreadData* data = - isolate_->FindPerThreadDataForThisThread(); + Isolate::PerIsolateThreadData* data = Isolate::CurrentPerIsolateThreadData(); return data != NULL && data->thread_state() != NULL; } + void ThreadManager::Iterate(ObjectVisitor* v) { // Expecting no threads during serialization/deserialization for (ThreadState* state = FirstThreadStateInUse(); diff --git a/test/cctest/SConscript b/test/cctest/SConscript index e2b0fc9f51..f4cb4a9a60 100644 --- a/test/cctest/SConscript +++ b/test/cctest/SConscript @@ -64,7 +64,6 @@ SOURCES = { 'test-list.cc', 'test-liveedit.cc', 'test-lock.cc', - 'test-lockers.cc', 'test-log-utils.cc', 'test-log.cc', 'test-mark-compact.cc', diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index 51a5fc7dec..aa2b355831 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -93,7 +93,6 @@ 'test-list.cc', 'test-liveedit.cc', 'test-lock.cc', - 'test-lockers.cc', 'test-log.cc', 'test-log-utils.cc', 'test-mark-compact.cc', diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index c2ab00d7d4..a228a6f499 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -30,7 +30,6 @@ #include "v8.h" #include "api.h" -#include "isolate.h" #include "compilation-cache.h" #include "execution.h" #include "snapshot.h" @@ -13387,28 +13386,6 @@ TEST(MultipleIsolatesOnIndividualThreads) { isolate2->Dispose(); } -TEST(IsolateDifferentContexts) { - v8::Isolate* isolate = v8::Isolate::New(); - Persistent context; - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope; - context = v8::Context::New(); - v8::Context::Scope context_scope(context); - Local v = CompileRun("2"); - CHECK(v->IsNumber()); - CHECK_EQ(2, static_cast(v->NumberValue())); - } - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope; - context = v8::Context::New(); - v8::Context::Scope context_scope(context); - Local v = CompileRun("22"); - CHECK(v->IsNumber()); - CHECK_EQ(22, static_cast(v->NumberValue())); - } -} class InitDefaultIsolateThread : public v8::internal::Thread { public: diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc deleted file mode 100644 index a8bfe648d9..0000000000 --- a/test/cctest/test-lockers.cc +++ /dev/null @@ -1,605 +0,0 @@ -// Copyright 2007-2011 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 - -#include "v8.h" - -#include "api.h" -#include "isolate.h" -#include "compilation-cache.h" -#include "execution.h" -#include "snapshot.h" -#include "platform.h" -#include "utils.h" -#include "cctest.h" -#include "parser.h" -#include "unicode-inl.h" - -using ::v8::AccessorInfo; -using ::v8::Context; -using ::v8::Extension; -using ::v8::Function; -using ::v8::HandleScope; -using ::v8::Local; -using ::v8::Object; -using ::v8::ObjectTemplate; -using ::v8::Persistent; -using ::v8::Script; -using ::v8::String; -using ::v8::Value; -using ::v8::V8; - -namespace i = ::i; - - - - -// Migrating an isolate -class KangarooThread : public v8::internal::Thread { - public: - KangarooThread(v8::Isolate* isolate, - v8::Handle context, int value) - : Thread(NULL, "KangarooThread"), - isolate_(isolate), context_(context), value_(value) { - } - - void Run() { - { - v8::Locker locker(isolate_); - v8::Isolate::Scope isolate_scope(isolate_); - CHECK_EQ(isolate_, v8::internal::Isolate::Current()); - v8::HandleScope scope; - v8::Context::Scope context_scope(context_); - Local v = CompileRun("getValue()"); - CHECK(v->IsNumber()); - CHECK_EQ(30, static_cast(v->NumberValue())); - } - { - v8::Locker locker(isolate_); - v8::Isolate::Scope isolate_scope(isolate_); - v8::Context::Scope context_scope(context_); - v8::HandleScope scope; - Local v = CompileRun("getValue()"); - CHECK(v->IsNumber()); - CHECK_EQ(30, static_cast(v->NumberValue())); - } - isolate_->Dispose(); - } - - private: - v8::Isolate* isolate_; - Persistent context_; - int value_; -}; - -// Migrates an isolate from one thread to another -TEST(KangarooIsolates) { - v8::Isolate* isolate = v8::Isolate::New(); - Persistent context; - { - v8::Locker locker(isolate); - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope; - context = v8::Context::New(); - v8::Context::Scope context_scope(context); - CHECK_EQ(isolate, v8::internal::Isolate::Current()); - CompileRun("function getValue() { return 30; }"); - } - KangarooThread thread1(isolate, context, 1); - thread1.Start(); - thread1.Join(); -} - -static void CalcFibAndCheck() { - Local v = CompileRun("function fib(n) {" - " if (n <= 2) return 1;" - " return fib(n-1) + fib(n-2);" - "}" - "fib(10)"); - CHECK(v->IsNumber()); - CHECK_EQ(55, static_cast(v->NumberValue())); -} - -class JoinableThread { - public: - explicit JoinableThread(const char* name) - : name_(name), - semaphore_(i::OS::CreateSemaphore(0)), - thread_(this) { - } - - virtual ~JoinableThread() { - delete semaphore_; - } - - void Start() { - thread_.Start(); - } - - void Join() { - semaphore_->Wait(); - } - - virtual void Run() = 0; - private: - class ThreadWithSemaphore : public i::Thread { - public: - explicit ThreadWithSemaphore(JoinableThread* joinable_thread) - : Thread(NULL, joinable_thread->name_), - joinable_thread_(joinable_thread) { - } - - virtual void Run() { - joinable_thread_->Run(); - joinable_thread_->semaphore_->Signal(); - } - - private: - JoinableThread* joinable_thread_; - }; - - const char* name_; - i::Semaphore* semaphore_; - ThreadWithSemaphore thread_; - - friend class ThreadWithSemaphore; - - DISALLOW_COPY_AND_ASSIGN(JoinableThread); -}; - - -class IsolateLockingThreadWithLocalContext : public JoinableThread { - public: - explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate) - : JoinableThread("IsolateLockingThread"), - isolate_(isolate) { - } - - virtual void Run() { - v8::Locker locker(isolate_); - v8::Isolate::Scope isolate_scope(isolate_); - v8::HandleScope handle_scope; - LocalContext local_context; - CHECK_EQ(isolate_, v8::internal::Isolate::Current()); - CalcFibAndCheck(); - } - private: - v8::Isolate* isolate_; -}; - -static void StartJoinAndDeleteThreads(const i::List& threads) { - for (int i = 0; i < threads.length(); i++) { - threads[i]->Start(); - } - for (int i = 0; i < threads.length(); i++) { - threads[i]->Join(); - } - for (int i = 0; i < threads.length(); i++) { - delete threads[i]; - } -} - - -// Run many threads all locking on the same isolate -TEST(IsolateLockingStress) { - const int kNThreads = 100; - i::List threads(kNThreads); - v8::Isolate* isolate = v8::Isolate::New(); - for (int i = 0; i < kNThreads; i++) { - threads.Add(new IsolateLockingThreadWithLocalContext(isolate)); - } - StartJoinAndDeleteThreads(threads); - isolate->Dispose(); -} - -class IsolateNonlockingThread : public JoinableThread { - public: - explicit IsolateNonlockingThread() - : JoinableThread("IsolateNonlockingThread") { - } - - virtual void Run() { - v8::Isolate* isolate = v8::Isolate::New(); - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope; - v8::Handle context = v8::Context::New(); - v8::Context::Scope context_scope(context); - CHECK_EQ(isolate, v8::internal::Isolate::Current()); - CalcFibAndCheck(); - } - isolate->Dispose(); - } - private: -}; - -// Run many threads each accessing its own isolate without locking -TEST(MultithreadedParallelIsolates) { - const int kNThreads = 50; - i::List threads(kNThreads); - for (int i = 0; i < kNThreads; i++) { - threads.Add(new IsolateNonlockingThread()); - } - StartJoinAndDeleteThreads(threads); -} - - -class IsolateNestedLockingThread : public JoinableThread { - public: - explicit IsolateNestedLockingThread(v8::Isolate* isolate) - : JoinableThread("IsolateNestedLocking"), isolate_(isolate) { - } - virtual void Run() { - v8::Locker lock(isolate_); - v8::Isolate::Scope isolate_scope(isolate_); - v8::HandleScope handle_scope; - LocalContext local_context; - { - v8::Locker another_lock(isolate_); - CalcFibAndCheck(); - } - { - v8::Locker another_lock(isolate_); - CalcFibAndCheck(); - } - } - private: - v8::Isolate* isolate_; -}; - -// Run many threads with nested locks -TEST(IsolateNestedLocking) { - const int kNThreads = 100; - v8::Isolate* isolate = v8::Isolate::New(); - i::List threads(kNThreads); - for (int i = 0; i < kNThreads; i++) { - threads.Add(new IsolateNestedLockingThread(isolate)); - } - StartJoinAndDeleteThreads(threads); -} - - -class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread { - public: - SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1, - v8::Isolate* isolate2) - : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"), - isolate1_(isolate1), isolate2_(isolate2) { - } - - virtual void Run() { - v8::Locker lock(isolate1_); - v8::Isolate::Scope isolate_scope(isolate1_); - v8::HandleScope handle_scope; - LocalContext local_context; - - IsolateLockingThreadWithLocalContext threadB(isolate2_); - threadB.Start(); - CalcFibAndCheck(); - threadB.Join(); - } - private: - v8::Isolate* isolate1_; - v8::Isolate* isolate2_; -}; - -// Run parallel threads that lock and access different isolates in parallel -TEST(SeparateIsolatesLocksNonexclusive) { - const int kNThreads = 100; - v8::Isolate* isolate1 = v8::Isolate::New(); - v8::Isolate* isolate2 = v8::Isolate::New(); - i::List threads(kNThreads); - for (int i = 0; i < kNThreads; i++) { - threads.Add(new SeparateIsolatesLocksNonexclusiveThread(isolate1, - isolate2)); - } - StartJoinAndDeleteThreads(threads); - isolate2->Dispose(); - isolate1->Dispose(); -} - -class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread { - public: - explicit LockIsolateAndCalculateFibSharedContextThread( - v8::Isolate* isolate, v8::Handle context) - : JoinableThread("LockIsolateAndCalculateFibThread"), - isolate_(isolate), - context_(context) { - } - - virtual void Run() { - v8::Locker lock(isolate_); - v8::Isolate::Scope isolate_scope(isolate_); - HandleScope handle_scope; - v8::Context::Scope context_scope(context_); - CalcFibAndCheck(); - } - private: - v8::Isolate* isolate_; - Persistent context_; -}; - -class LockerUnlockerThread : public JoinableThread { - public: - explicit LockerUnlockerThread(v8::Isolate* isolate) - : JoinableThread("LockerUnlockerThread"), - isolate_(isolate) { - } - - virtual void Run() { - v8::Locker lock(isolate_); - v8::Isolate::Scope isolate_scope(isolate_); - v8::HandleScope handle_scope; - v8::Handle context = v8::Context::New(); - { - v8::Context::Scope context_scope(context); - CalcFibAndCheck(); - } - { - isolate_->Exit(); - v8::Unlocker unlocker(isolate_); - LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context); - thread.Start(); - thread.Join(); - } - isolate_->Enter(); - { - v8::Context::Scope context_scope(context); - CalcFibAndCheck(); - } - } - private: - v8::Isolate* isolate_; -}; - -// Use unlocker inside of a Locker, multiple threads. -TEST(LockerUnlocker) { - const int kNThreads = 100; - i::List threads(kNThreads); - v8::Isolate* isolate = v8::Isolate::New(); - for (int i = 0; i < kNThreads; i++) { - threads.Add(new LockerUnlockerThread(isolate)); - } - StartJoinAndDeleteThreads(threads); - isolate->Dispose(); -} - -class LockTwiceAndUnlockThread : public JoinableThread { - public: - explicit LockTwiceAndUnlockThread(v8::Isolate* isolate) - : JoinableThread("LockTwiceAndUnlockThread"), - isolate_(isolate) { - } - - virtual void Run() { - v8::Locker lock(isolate_); - v8::Isolate::Scope isolate_scope(isolate_); - v8::HandleScope handle_scope; - v8::Handle context = v8::Context::New(); - { - v8::Context::Scope context_scope(context); - CalcFibAndCheck(); - } - { - v8::Locker second_lock(isolate_); - { - isolate_->Exit(); - v8::Unlocker unlocker(isolate_); - LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context); - thread.Start(); - thread.Join(); - } - } - isolate_->Enter(); - { - v8::Context::Scope context_scope(context); - CalcFibAndCheck(); - } - } - private: - v8::Isolate* isolate_; -}; - -// Use Unlocker inside two Lockers. -TEST(LockTwiceAndUnlock) { - const int kNThreads = 100; - i::List threads(kNThreads); - v8::Isolate* isolate = v8::Isolate::New(); - for (int i = 0; i < kNThreads; i++) { - threads.Add(new LockTwiceAndUnlockThread(isolate)); - } - StartJoinAndDeleteThreads(threads); - isolate->Dispose(); -} - -class LockAndUnlockDifferentIsolatesThread : public JoinableThread { - public: - LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1, - v8::Isolate* isolate2) - : JoinableThread("LockAndUnlockDifferentIsolatesThread"), - isolate1_(isolate1), - isolate2_(isolate2) { - } - - virtual void Run() { - Persistent context1; - Persistent context2; - v8::Locker lock1(isolate1_); - CHECK(v8::Locker::IsLocked(isolate1_)); - CHECK(!v8::Locker::IsLocked(isolate2_)); - { - v8::Isolate::Scope isolate_scope(isolate1_); - v8::HandleScope handle_scope; - context1 = v8::Context::New(); - { - v8::Context::Scope context_scope(context1); - CalcFibAndCheck(); - } - } - v8::Locker lock2(isolate2_); - CHECK(v8::Locker::IsLocked(isolate1_)); - CHECK(v8::Locker::IsLocked(isolate2_)); - { - v8::Isolate::Scope isolate_scope(isolate2_); - v8::HandleScope handle_scope; - context2 = v8::Context::New(); - { - v8::Context::Scope context_scope(context2); - CalcFibAndCheck(); - } - } - { - v8::Unlocker unlock1(isolate1_); - CHECK(!v8::Locker::IsLocked(isolate1_)); - CHECK(v8::Locker::IsLocked(isolate2_)); - v8::Isolate::Scope isolate_scope(isolate2_); - v8::HandleScope handle_scope; - v8::Context::Scope context_scope(context2); - LockIsolateAndCalculateFibSharedContextThread thread(isolate1_, context1); - thread.Start(); - CalcFibAndCheck(); - thread.Join(); - } - } - private: - v8::Isolate* isolate1_; - v8::Isolate* isolate2_; -}; - -// Lock two isolates and unlock one of them. -TEST(LockAndUnlockDifferentIsolates) { - v8::Isolate* isolate1 = v8::Isolate::New(); - v8::Isolate* isolate2 = v8::Isolate::New(); - LockAndUnlockDifferentIsolatesThread thread(isolate1, isolate2); - thread.Start(); - thread.Join(); - isolate2->Dispose(); - isolate1->Dispose(); -} - -class LockUnlockLockThread : public JoinableThread { - public: - LockUnlockLockThread(v8::Isolate* isolate, v8::Handle context) - : JoinableThread("LockUnlockLockThread"), - isolate_(isolate), - context_(context) { - } - - virtual void Run() { - v8::Locker lock1(isolate_); - CHECK(v8::Locker::IsLocked(isolate_)); - CHECK(!v8::Locker::IsLocked()); - { - v8::Isolate::Scope isolate_scope(isolate_); - v8::HandleScope handle_scope; - v8::Context::Scope context_scope(context_); - CalcFibAndCheck(); - } - { - v8::Unlocker unlock1(isolate_); - CHECK(!v8::Locker::IsLocked(isolate_)); - CHECK(!v8::Locker::IsLocked()); - { - v8::Locker lock2(isolate_); - v8::Isolate::Scope isolate_scope(isolate_); - v8::HandleScope handle_scope; - CHECK(v8::Locker::IsLocked(isolate_)); - CHECK(!v8::Locker::IsLocked()); - v8::Context::Scope context_scope(context_); - CalcFibAndCheck(); - } - } - } - - private: - v8::Isolate* isolate_; - v8::Persistent context_; -}; - -// Locker inside an Unlocker inside a Locker. -TEST(LockUnlockLockMultithreaded) { - const int kNThreads = 100; - v8::Isolate* isolate = v8::Isolate::New(); - Persistent context; - { - v8::Locker locker_(isolate); - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope; - context = v8::Context::New(); - } - i::List threads(kNThreads); - for (int i = 0; i < kNThreads; i++) { - threads.Add(new LockUnlockLockThread(isolate, context)); - } - StartJoinAndDeleteThreads(threads); -} - -class LockUnlockLockDefaultIsolateThread : public JoinableThread { - public: - LockUnlockLockDefaultIsolateThread(v8::Handle context) - : JoinableThread("LockUnlockLockDefaultIsolateThread"), - context_(context) { - } - - virtual void Run() { - v8::Locker lock1; - { - v8::HandleScope handle_scope; - v8::Context::Scope context_scope(context_); - CalcFibAndCheck(); - } - { - v8::Unlocker unlock1; - { - v8::Locker lock2; - v8::HandleScope handle_scope; - v8::Context::Scope context_scope(context_); - CalcFibAndCheck(); - } - } - } - - private: - v8::Persistent context_; -}; - -// Locker inside an Unlocker inside a Locker for default isolate. -TEST(LockUnlockLockDefaultIsolateMultithreaded) { - const int kNThreads = 100; - Persistent context; - { - v8::Locker locker_; - v8::HandleScope handle_scope; - context = v8::Context::New(); - } - i::List threads(kNThreads); - for (int i = 0; i < kNThreads; i++) { - threads.Add(new LockUnlockLockDefaultIsolateThread(context)); - } - StartJoinAndDeleteThreads(threads); -}