]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSLock.h
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / runtime / JSLock.h
index 8b015c4c88d44c9ee56c49658558138e23400d33..c757b4f2653472fbb5cc1c6ee23540c06d82a0bb 100644 (file)
@@ -23,6 +23,9 @@
 
 #include <wtf/Assertions.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+#include <wtf/TCSpinLock.h>
+#include <wtf/Threading.h>
 
 namespace JSC {
 
@@ -30,8 +33,9 @@ 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.
 
@@ -44,59 +48,87 @@ namespace JSC {
     // 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