#include <wtf/Assertions.h>
#include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+#include <wtf/TCSpinLock.h>
+#include <wtf/Threading.h>
namespace JSC {
// important to lock before doing anything that allocates a
// JavaScript data structure or that interacts with shared state
// such as the protect count hash table. The simplest way to lock
- // is to create a local JSLock object in the scope where the lock
- // must be held. The lock is recursive so nesting is ok. The JSLock
+ // is to create a local JSLockHolder object in the scope where the lock
+ // must be held and pass it the context that requires protection.
+ // The lock is recursive so nesting is ok. The JSLock
// object also acts as a convenience short-hand for running important
// initialization routines.
// DropAllLocks object takes care to release the JSLock only if your
// thread acquired it to begin with.
- // For contexts other than the single shared one, implicit locking is not done,
- // but we still need to perform all the counting in order to keep debug
- // assertions working, so that clients that use the shared context don't break.
-
class ExecState;
+ class VM;
- enum JSLockBehavior { SilenceAssertionsOnly, LockForReal };
+ // This class is used to protect the initialization of the legacy single
+ // shared VM.
+ class GlobalJSLock {
+ WTF_MAKE_NONCOPYABLE(GlobalJSLock);
+ public:
+ JS_EXPORT_PRIVATE GlobalJSLock();
+ JS_EXPORT_PRIVATE ~GlobalJSLock();
- class JSLock : public Noncopyable {
+ static void initialize();
+ private:
+ static Mutex* s_sharedInstanceLock;
+ };
+
+ class JSLockHolder {
public:
- JSLock(ExecState*);
-
- JSLock(JSLockBehavior lockBehavior)
- : m_lockBehavior(lockBehavior)
- {
-#ifdef NDEBUG
- // Locking "not for real" is a debug-only feature.
- if (lockBehavior == SilenceAssertionsOnly)
- return;
-#endif
- lock(lockBehavior);
- }
-
- ~JSLock()
- {
-#ifdef NDEBUG
- // Locking "not for real" is a debug-only feature.
- if (m_lockBehavior == SilenceAssertionsOnly)
- return;
-#endif
- unlock(m_lockBehavior);
- }
-
- static void lock(JSLockBehavior);
- static void unlock(JSLockBehavior);
+ JS_EXPORT_PRIVATE JSLockHolder(VM*);
+ JS_EXPORT_PRIVATE JSLockHolder(VM&);
+ JS_EXPORT_PRIVATE JSLockHolder(ExecState*);
+
+ JS_EXPORT_PRIVATE ~JSLockHolder();
+ private:
+ void init();
+
+ RefPtr<VM> m_vm;
+ };
+
+ class JSLock : public ThreadSafeRefCounted<JSLock> {
+ WTF_MAKE_NONCOPYABLE(JSLock);
+ public:
+ JSLock(VM*);
+ JS_EXPORT_PRIVATE ~JSLock();
+
+ JS_EXPORT_PRIVATE void lock();
+ JS_EXPORT_PRIVATE void unlock();
+
static void lock(ExecState*);
static void unlock(ExecState*);
+ static void lock(VM&);
+ static void unlock(VM&);
- static intptr_t lockCount();
- static bool currentThreadIsHoldingLock();
+ VM* vm() { return m_vm; }
- JSLockBehavior m_lockBehavior;
+ JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock();
- class DropAllLocks : public Noncopyable {
+ unsigned dropAllLocks(SpinLock&);
+ unsigned dropAllLocksUnconditionally(SpinLock&);
+ void grabAllLocks(unsigned lockCount, SpinLock&);
+
+ void willDestroyVM(VM*);
+
+ class DropAllLocks {
+ WTF_MAKE_NONCOPYABLE(DropAllLocks);
public:
- DropAllLocks(ExecState* exec);
- DropAllLocks(JSLockBehavior);
- ~DropAllLocks();
+#if PLATFORM(IOS)
+ // This is a hack to allow Mobile Safari to always release the locks since
+ // hey depend on the behavior that DropAllLocks does indeed always drop all
+ // locks, which isn't always the case with the default behavior.
+ enum AlwaysDropLocksTag { DontAlwaysDropLocks = 0, AlwaysDropLocks };
+ JS_EXPORT_PRIVATE DropAllLocks(ExecState* exec, AlwaysDropLocksTag alwaysDropLocks = DontAlwaysDropLocks);
+ JS_EXPORT_PRIVATE DropAllLocks(VM*, AlwaysDropLocksTag alwaysDropLocks = DontAlwaysDropLocks);
+#else
+ JS_EXPORT_PRIVATE DropAllLocks(ExecState* exec);
+ JS_EXPORT_PRIVATE DropAllLocks(VM*);
+#endif
+ JS_EXPORT_PRIVATE ~DropAllLocks();
private:
intptr_t m_lockCount;
- JSLockBehavior m_lockBehavior;
+ RefPtr<VM> m_vm;
};
+
+ private:
+ SpinLock m_spinLock;
+ Mutex m_lock;
+ ThreadIdentifier m_ownerThread;
+ intptr_t m_lockCount;
+ unsigned m_lockDropDepth;
+ VM* m_vm;
};
} // namespace