Reviewed by Geoff and Adam.
authormjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Mar 2007 23:57:01 +0000 (23:57 +0000)
committermjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Mar 2007 23:57:01 +0000 (23:57 +0000)
        - make USE(MULTIPLE_THREADS) support more portable
        http://bugs.webkit.org/show_bug.cgi?id=13069

        - fixed a threadsafety bug discovered by testing this

        - enhanced threadsafety assertions in collector

        * API/JSCallbackObject.cpp:
        (KJS::JSCallbackObject::~JSCallbackObject): This destructor can't
        DropAllLocks around the finalize callback, because it gets called
        from garbage collection and we can't let other threads collect!

        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
        * kjs/JSLock.cpp:
        (KJS::JSLock::currentThreadIsHoldingLock): Added new function
        to allow stronger assertions than just that the lock is held
        by some thread (you can now assert that the current thread is
        holding it, given the new JSLock design).
        * kjs/JSLock.h:
        * kjs/collector.cpp: Refactored for portability plus added some
        stronger assertions.
        (KJS::Collector::allocate):
        (KJS::currentThreadStackBase):
        (KJS::Collector::registerAsMainThread):
        (KJS::onMainThread):
        (KJS::PlatformThread::PlatformThread):
        (KJS::getCurrentPlatformThread):
        (KJS::Collector::Thread::Thread):
        (KJS::destroyRegisteredThread):
        (KJS::Collector::registerThread):
        (KJS::Collector::markCurrentThreadConservatively):
        (KJS::suspendThread):
        (KJS::resumeThread):
        (KJS::getPlatformThreadRegisters):
        (KJS::otherThreadStackPointer):
        (KJS::otherThreadStackBase):
        (KJS::Collector::markOtherThreadConservatively):
        (KJS::Collector::markStackObjectsConservatively):
        (KJS::Collector::protect):
        (KJS::Collector::unprotect):
        (KJS::Collector::collectOnMainThreadOnly):
        (KJS::Collector::markMainThreadOnlyObjects):
        (KJS::Collector::collect):
        * kjs/collector.h:
        * wtf/FastMalloc.cpp:
        (WTF::fastMallocSetIsMultiThreaded):
        * wtf/FastMallocInternal.h:
        * wtf/Platform.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@20351 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/API/JSCallbackObject.cpp
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
JavaScriptCore/kjs/JSLock.cpp
JavaScriptCore/kjs/JSLock.h
JavaScriptCore/kjs/collector.cpp
JavaScriptCore/kjs/collector.h
JavaScriptCore/wtf/FastMalloc.cpp
JavaScriptCore/wtf/FastMallocInternal.h
JavaScriptCore/wtf/Platform.h

index 73752f113f69e94e57e87c2145b58b53b71b7640..68252a04242f140bcde81b0132d0dcaeac70fe96 100644 (file)
@@ -71,7 +71,6 @@ JSCallbackObject::~JSCallbackObject()
     
     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
         if (JSObjectFinalizeCallback finalize = jsClass->finalize) {
-            JSLock::DropAllLocks dropAllLocks;
             finalize(thisRef);
         }
     
index c513f0ab4fb1b61aeef2f200599b2f7be0caad35..45b9d0215cc2d7ae9fe35cf2cfbe6fd958ee524b 100644 (file)
@@ -1,3 +1,56 @@
+2007-03-20  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Geoff and Adam.
+        
+        - make USE(MULTIPLE_THREADS) support more portable
+        http://bugs.webkit.org/show_bug.cgi?id=13069
+        
+        - fixed a threadsafety bug discovered by testing this
+        
+        - enhanced threadsafety assertions in collector
+
+        * API/JSCallbackObject.cpp:
+        (KJS::JSCallbackObject::~JSCallbackObject): This destructor can't
+        DropAllLocks around the finalize callback, because it gets called
+        from garbage collection and we can't let other threads collect!
+
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * kjs/JSLock.cpp:
+        (KJS::JSLock::currentThreadIsHoldingLock): Added new function
+        to allow stronger assertions than just that the lock is held
+        by some thread (you can now assert that the current thread is
+        holding it, given the new JSLock design).
+        * kjs/JSLock.h:
+        * kjs/collector.cpp: Refactored for portability plus added some
+        stronger assertions.
+        (KJS::Collector::allocate):
+        (KJS::currentThreadStackBase):
+        (KJS::Collector::registerAsMainThread):
+        (KJS::onMainThread):
+        (KJS::PlatformThread::PlatformThread):
+        (KJS::getCurrentPlatformThread):
+        (KJS::Collector::Thread::Thread):
+        (KJS::destroyRegisteredThread):
+        (KJS::Collector::registerThread):
+        (KJS::Collector::markCurrentThreadConservatively):
+        (KJS::suspendThread):
+        (KJS::resumeThread):
+        (KJS::getPlatformThreadRegisters):
+        (KJS::otherThreadStackPointer):
+        (KJS::otherThreadStackBase):
+        (KJS::Collector::markOtherThreadConservatively):
+        (KJS::Collector::markStackObjectsConservatively):
+        (KJS::Collector::protect):
+        (KJS::Collector::unprotect):
+        (KJS::Collector::collectOnMainThreadOnly):
+        (KJS::Collector::markMainThreadOnlyObjects):
+        (KJS::Collector::collect):
+        * kjs/collector.h:
+        * wtf/FastMalloc.cpp:
+        (WTF::fastMallocSetIsMultiThreaded):
+        * wtf/FastMallocInternal.h:
+        * wtf/Platform.h:
+
 2007-03-19  Darin Adler  <darin@apple.com>
 
         * kjs/value.h: Roll ~JSValue change out. It was causing problems. I'll do it right later.
index c039c8575f65407ce6eea96567ecfaf30114fddf..e7b700c959749917c05bbc471911329fd8b73491 100644 (file)
@@ -46,7 +46,7 @@
                        <Tool
                                Name="VCCLCompilerTool"
                                Optimization="0"
-                               AdditionalIncludeDirectories="&quot;$(WebKitOutputDir)\obj\JavaScriptCore\$(ConfigurationName)\DerivedSources\&quot;;../../;&quot;../../os-win32/&quot;;../../pcre/;../../kjs/;../../wtf/;&quot;$(WebKitSDKDir)\include&quot;;&quot;$(WebKitSDKDir)\include\icu&quot;;../../../icu/include;../../bindings;../../bindings/c;../../bindings/jni;&quot;$(WebKitOutputDir)\include\JavaScriptCore&quot;"
+                               AdditionalIncludeDirectories="&quot;$(WebKitOutputDir)\obj\JavaScriptCore\$(ConfigurationName)\DerivedSources\&quot;;../../;&quot;../../os-win32/&quot;;../../pcre/;../../kjs/;../../wtf/;&quot;$(WebKitSDKDir)\include&quot;;&quot;$(WebKitSDKDir)\include\icu&quot;;../../../icu/include;../../bindings;../../bindings/c;../../bindings/jni;&quot;$(WebKitOutputDir)\include\JavaScriptCore&quot;;&quot;$(WebKitSDKDir)\include\pthreads&quot;"
                                PreprocessorDefinitions="HAVE_CONFIG_H;WIN32;__STD_C;_SCL_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
                                MinimalRebuild="true"
                                ExceptionHandling="0"
                        />
                        <Tool
                                Name="VCCLCompilerTool"
-                               AdditionalIncludeDirectories="&quot;$(WebKitOutputDir)\obj\JavaScriptCore\$(ConfigurationName)\DerivedSources\&quot;;../../;&quot;../../os-win32/&quot;;../../pcre/;../../kjs/;../../wtf/;&quot;$(WebKitSDKDir)\include&quot;;&quot;$(WebKitSDKDir)\include\icu&quot;;../../../icu/include;../../bindings;../../bindings/c;../../bindings/jni;&quot;$(WebKitOutputDir)\include\JavaScriptCore&quot;"
+                               AdditionalIncludeDirectories="&quot;$(WebKitOutputDir)\obj\JavaScriptCore\$(ConfigurationName)\DerivedSources\&quot;;../../;&quot;../../os-win32/&quot;;../../pcre/;../../kjs/;../../wtf/;&quot;$(WebKitSDKDir)\include&quot;;&quot;$(WebKitSDKDir)\include\icu&quot;;../../../icu/include;../../bindings;../../bindings/c;../../bindings/jni;&quot;$(WebKitOutputDir)\include\JavaScriptCore&quot;;&quot;$(WebKitSDKDir)\include\pthreads&quot;"
                                PreprocessorDefinitions="HAVE_CONFIG_H;WIN32;__STD_C;NDEBUG;_SCL_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE"
                                ExceptionHandling="0"
                                RuntimeLibrary="2"
index c28450a372cdf361006fd066f46c0afccee564f6..7f13e352978b8f35006ac9d0cb59db05eba3646f 100644 (file)
@@ -24,6 +24,9 @@
 #include "JSLock.h"
 
 #include "collector.h"
+#if USE(MULTIPLE_THREADS)
+#include <pthread.h>
+#endif
 
 namespace KJS {
 
@@ -67,6 +70,12 @@ void JSLock::unlock()
     }
 }
 
+bool JSLock::currentThreadIsHoldingLock()
+{
+    pthread_once(&createDidLockJSMutexOnce, createDidLockJSMutex);
+    return !!pthread_getspecific(didLockJSMutex);
+}
+
 void JSLock::registerThread()
 {
     Collector::registerThread();
index 9ddf6f18e2d1b362402624e312a1322ee3650620..ae0e7f4ab3c34e5eec7bacc659e921d762275b8e 100644 (file)
@@ -62,6 +62,7 @@ namespace KJS {
         static void lock();
         static void unlock();
         static int lockCount();
+        static bool currentThreadIsHoldingLock();
 
         static void registerThread();
 
index eac0c82a3aecbe16d32a7a7452703a180c066758..9b7eeffd7c3f44be2340b04b6b3ecb6372d61720 100644 (file)
 #include <setjmp.h>
 #include <algorithm>
 
+#include <pthread.h>
+
 #if PLATFORM(DARWIN)
 
-#include <pthread.h>
 #include <mach/mach_port.h>
 #include <mach/task.h>
 #include <mach/thread_act.h>
@@ -45,8 +46,6 @@
 
 #elif PLATFORM(UNIX)
 
-#include <pthread.h>
-
 #if HAVE(PTHREAD_NP_H)
 #include <pthread_np.h>
 #endif
@@ -112,6 +111,7 @@ size_t Collector::mainThreadOnlyObjectCount = 0;
 bool Collector::memoryFull = false;
 
 #ifndef NDEBUG
+
 class GCLock {
     static bool isLocked;
 
@@ -134,7 +134,8 @@ bool GCLock::isLocked = false;
 
 void* Collector::allocate(size_t s)
 {
-  assert(JSLock::lockCount() > 0);
+  ASSERT(JSLock::lockCount() > 0);
+  ASSERT(JSLock::currentThreadIsHoldingLock());
 
   // collect if needed
   size_t numLiveObjects = heap.numLiveObjects;
@@ -179,13 +180,13 @@ void* Collector::allocate(size_t s)
   if (i != usedBlocks) {
     targetBlock = heap.blocks[i];
     targetBlockUsedCells = targetBlock->usedCells;
-    assert(targetBlockUsedCells <= CELLS_PER_BLOCK);
+    ASSERT(targetBlockUsedCells <= CELLS_PER_BLOCK);
     while (targetBlockUsedCells == CELLS_PER_BLOCK) {
       if (++i == usedBlocks)
         goto allocateNewBlock;
       targetBlock = heap.blocks[i];
       targetBlockUsedCells = targetBlock->usedCells;
-      assert(targetBlockUsedCells <= CELLS_PER_BLOCK);
+      ASSERT(targetBlockUsedCells <= CELLS_PER_BLOCK);
     }
     heap.firstBlockWithPossibleSpace = i;
   } else {
@@ -219,22 +220,98 @@ allocateNewBlock:
   return newCell;
 }
 
+static inline void* currentThreadStackBase()
+{
+#if PLATFORM(DARWIN)
+    pthread_t thread = pthread_self();
+    return pthread_get_stackaddr_np(thread);
+#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(MSVC)
+    // offset 0x18 from the FS segment register gives a pointer to
+    // the thread information block for the current thread
+    NT_TIB* pTib;
+    __asm {
+        MOV EAX, FS:[18h]
+        MOV pTib, EAX
+    }
+    return (void*)pTib->StackBase;
+#elif PLATFORM(UNIX)
+    static void *stackBase = 0;
+    static pthread_t stackThread;
+    pthread_t thread = pthread_self();
+    if (stackBase == 0 || thread != stackThread) {
+        pthread_attr_t sattr;
+#if HAVE(PTHREAD_NP_H)
+        // e.g. on FreeBSD 5.4, neundorf@kde.org
+        pthread_attr_get_np(thread, &sattr);
+#else
+        // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
+        pthread_getattr_np(thread, &sattr);
+#endif
+        size_t stackSize;
+        int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
+        (void)rc; // FIXME: deal with error code somehow?  seems fatal...
+        ASSERT(stackBase);
+        return (void*)(size_t(stackBase) + stackSize);
+        stackThread = thread;
+    }
+#else
+#error Need a way to get the stack base on this platform
+#endif
+}
+
+static pthread_t mainThread;
+
+void Collector::registerAsMainThread()
+{
+    mainThread = pthread_self();
+}
+
+static inline bool onMainThread()
+{
+#if PLATFORM(DARWIN)
+    return pthread_main_np();
+#else
+    return !!pthread_equal(pthread_self(), mainThread);
+#endif
+}
+
 #if USE(MULTIPLE_THREADS)
 
-struct Collector::Thread {
-  Thread(pthread_t pthread, mach_port_t mthread) : posixThread(pthread), machThread(mthread) {}
-  Thread *next;
+#if PLATFORM(DARWIN)
+typedef mach_port_t PlatformThread;
+#elif PLATFORM(WIN_OS)
+struct PlatformThread {
+    PlatformThread(DWORD _id, HANDLE _handle) : id(_id), handle(_handle) {}
+    DWORD id;
+    HANDLE handle;
+};
+#endif
+
+static inline PlatformThread getCurrentPlatformThread()
+{
+#if PLATFORM(DARWIN)
+    return pthread_mach_thread_np(pthread_self());
+#elif PLATFORM(WIN_OS)
+    HANDLE threadHandle = pthread_getw32threadhandle_np(pthread_self());
+    return PlatformThread(GetCurrentThreadId(), threadHandle);
+#endif
+}
+
+class Collector::Thread {
+public:
+  Thread(pthread_t pthread, const PlatformThread& platThread) : posixThread(pthread), platformThread(platThread) {}
+  Thread* next;
   pthread_t posixThread;
-  mach_port_t machThread;
+  PlatformThread platformThread;
 };
 
 pthread_key_t registeredThreadKey;
 pthread_once_t registeredThreadKeyOnce = PTHREAD_ONCE_INIT;
-Collector::Thread *registeredThreads;
-  
-static void destroyRegisteredThread(void *data) 
+Collector::ThreadregisteredThreads;
+
+static void destroyRegisteredThread(voiddata) 
 {
-  Collector::Thread *thread = (Collector::Thread *)data;
+  Collector::Thread* thread = (Collector::Thread*)data;
 
   // Can't use JSLock convenience object here because we don't want to re-register
   // an exiting thread.
@@ -246,8 +323,8 @@ static void destroyRegisteredThread(void *data)
     Collector::Thread *last = registeredThreads;
     Collector::Thread *t;
     for (t = registeredThreads->next; t != NULL; t = t->next) {
-      if (t == thread) {
-        last->next = t->next;
+      if (t == thread) {          
+          last->next = t->next;
           break;
       }
       last = t;
@@ -268,14 +345,15 @@ static void initializeRegisteredThreadKey()
 void Collector::registerThread()
 {
   ASSERT(JSLock::lockCount() > 0);
+  ASSERT(JSLock::currentThreadIsHoldingLock());
   
   pthread_once(&registeredThreadKeyOnce, initializeRegisteredThreadKey);
 
   if (!pthread_getspecific(registeredThreadKey)) {
-    if (!pthread_main_np())
+    if (!onMainThread())
         WTF::fastMallocSetIsMultiThreaded();
-    pthread_t pthread = pthread_self();
-    Collector::Thread *thread = new Collector::Thread(pthread, pthread_mach_thread_np(pthread));
+    Collector::Thread *thread = new Collector::Thread(pthread_self(), getCurrentPlatformThread());
+
     thread->next = registeredThreads;
     registeredThreads = thread;
     pthread_setspecific(registeredThreadKey, thread);
@@ -297,9 +375,9 @@ void Collector::markStackObjectsConservatively(void *start, void *end)
     end = tmp;
   }
 
-  assert(((char *)end - (char *)start) < 0x1000000);
-  assert(IS_POINTER_ALIGNED(start));
-  assert(IS_POINTER_ALIGNED(end));
+  ASSERT(((char *)end - (char *)start) < 0x1000000);
+  ASSERT(IS_POINTER_ALIGNED(start));
+  ASSERT(IS_POINTER_ALIGNED(end));
   
   char **p = (char **)start;
   char **e = (char **)end;
@@ -336,6 +414,7 @@ gotGoodPointer:
 
 void Collector::markCurrentThreadConservatively()
 {
+    // setjmp forces volatile registers onto the stack
     jmp_buf registers;
 #if COMPILER(MSVC)
 #pragma warning(push)
@@ -346,97 +425,163 @@ void Collector::markCurrentThreadConservatively()
 #pragma warning(pop)
 #endif
 
+    void* dummy;
+    void* stackPointer = &dummy;
+    void* stackBase = currentThreadStackBase();
+
+    markStackObjectsConservatively(stackPointer, stackBase);
+}
+
+#if USE(MULTIPLE_THREADS)
+
+static inline void suspendThread(const PlatformThread& platformThread)
+{
 #if PLATFORM(DARWIN)
-    pthread_t thread = pthread_self();
-    void *stackBase = pthread_get_stackaddr_np(thread);
-#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(MSVC)
-    NT_TIB *pTib;
-    __asm {
-        MOV EAX, FS:[18h]
-        MOV pTib, EAX
-    }
-    void *stackBase = (void *)pTib->StackBase;
-#elif PLATFORM(UNIX)
-    static void *stackBase = 0;
-    static pthread_t stackThread;
-    pthread_t thread = pthread_self();
-    if (stackBase == 0 || thread != stackThread) {
-        pthread_attr_t sattr;
-#if HAVE(PTHREAD_NP_H)
-        // e.g. on FreeBSD 5.4, neundorf@kde.org
-        pthread_attr_get_np(thread, &sattr);
+  thread_suspend(platformThread);
+#elif PLATFORM(WIN_OS)
+  SuspendThread(platformThread.handle);
 #else
-        // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
-        pthread_getattr_np(thread, &sattr);
+#error Need a way to suspend threads on this platform
 #endif
-        size_t stackSize;
-        int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
-        (void)rc; // FIXME: deal with error code somehow?  seems fatal...
-        assert(stackBase);
-        stackBase = (void*)(size_t(stackBase) + stackSize);
-        stackThread = thread;
-    }
+}
+
+static inline void resumeThread(const PlatformThread& platformThread)
+{
+#if PLATFORM(DARWIN)
+  thread_resume(platformThread);
+#elif PLATFORM(WIN_OS)
+  ResumeThread(platformThread.handle);
 #else
-#error Need a way to get the stack base on this platform
+#error Need a way to resume threads on this platform
 #endif
+}
 
-    void *dummy;
-    void *stackPointer = &dummy;
+typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
 
-    markStackObjectsConservatively(stackPointer, stackBase);
-}
+#if PLATFORM(DARWIN)
 
-#if USE(MULTIPLE_THREADS)
+#if     PLATFORM(X86)
+typedef i386_thread_state_t PlatformThreadRegisters;
+#elif   PLATFORM(X86_64)
+typedef x86_thread_state64_t PlatformThreadRegisters;
+#elif   PLATFORM(PPC)
+typedef ppc_thread_state_t PlatformThreadRegisters;
+#elif   PLATFORM(PPC64)
+typedef ppc_thread_state64_t PlatformThreadRegisters;
+#else
+#error Unknown Architecture
+#endif
 
-typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
+#elif PLATFORM(WIN_OS)&& PLATFORM(X86)
+typedef CONTEXT PlatformThreadRegisters;
+#else
+#error Need a thread register struct for this platform
+#endif
 
-void Collector::markOtherThreadConservatively(Thread *thread)
+size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs)
 {
-  thread_suspend(thread->machThread);
+#if PLATFORM(DARWIN)
 
-#if PLATFORM(X86)
-  i386_thread_state_t regs;
+#if     PLATFORM(X86)
   unsigned user_count = sizeof(regs)/sizeof(int);
   thread_state_flavor_t flavor = i386_THREAD_STATE;
-#elif PLATFORM(X86_64)
-  x86_thread_state64_t  regs;
+#elif   PLATFORM(X86_64)
   unsigned user_count = x86_THREAD_STATE64_COUNT;
   thread_state_flavor_t flavor = x86_THREAD_STATE64;
-#elif PLATFORM(PPC)
-  ppc_thread_state_t  regs;
+#elif   PLATFORM(PPC) 
   unsigned user_count = PPC_THREAD_STATE_COUNT;
   thread_state_flavor_t flavor = PPC_THREAD_STATE;
-#elif PLATFORM(PPC64)
-  ppc_thread_state64_t  regs;
+#elif   PLATFORM(PPC64)
   unsigned user_count = PPC_THREAD_STATE64_COUNT;
   thread_state_flavor_t flavor = PPC_THREAD_STATE64;
 #else
 #error Unknown Architecture
 #endif
-  // get the thread register state
-  thread_get_state(thread->machThread, flavor, (thread_state_t)&regs, &user_count);
-  
-  // scan the registers
-  markStackObjectsConservatively((void *)&regs, (void *)((char *)&regs + (user_count * sizeof(usword_t))));
-   
-  // scan the stack
-#if PLATFORM(X86) && __DARWIN_UNIX03
-  markStackObjectsConservatively((void *)regs.__esp, pthread_get_stackaddr_np(thread->posixThread));
-#elif PLATFORM(X86)
-  markStackObjectsConservatively((void *)regs.esp, pthread_get_stackaddr_np(thread->posixThread));
-#elif PLATFORM(X86_64) && __DARWIN_UNIX03
-  markStackObjectsConservatively((void *)regs.__rsp, pthread_get_stackaddr_np(thread->posixThread));
+
+  thread_get_state(platformThread, flavor, (thread_state_t)&regs, &user_count);
+  return user_count * sizeof(usword_t);
+// end PLATFORM(DARWIN)
+
+#elif PLATFORM(WIN_OS) && PLATFORM(X86)
+  regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS;
+  GetThreadContext(platformThread.handle, &regs);
+  return sizeof(CONTEXT);
+#else
+#error Need a way to get thread registers on this platform
+#endif
+}
+
+static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
+{
+#if PLATFORM(DARWIN)
+
+#if __DARWIN_UNIX03
+
+#if PLATFORM(X86)
+  return (void*)regs.__esp;
 #elif PLATFORM(X86_64)
-  markStackObjectsConservatively((void *)regs.rsp, pthread_get_stackaddr_np(thread->posixThread));
-#elif (PLATFORM(PPC) || PLATFORM(PPC64)) && __DARWIN_UNIX03
-  markStackObjectsConservatively((void *)regs.__r1, pthread_get_stackaddr_np(thread->posixThread));
+  return (void*)regs.__rsp;
 #elif PLATFORM(PPC) || PLATFORM(PPC64)
-  markStackObjectsConservatively((void *)regs.r1, pthread_get_stackaddr_np(thread->posixThread));
+  return (void*)regs.__r1;
+#else
+#error Unknown Architecture
+#endif
+
+#else // !__DARWIN_UNIX03
+
+#if PLATFORM(X86)
+  return (void*)regs.esp;
+#elif PLATFORM(X86_64)
+  return (void*)regs.rsp;
+#elif (PLATFORM(PPC) || PLATFORM(PPC64))
+  return (void*)regs.r1;
 #else
 #error Unknown Architecture
 #endif
 
-  thread_resume(thread->machThread);
+#endif // __DARWIN_UNIX03
+
+// end PLATFORM(DARWIN)
+#elif PLATFORM(X86) && PLATFORM(WIN_OS)
+  return (void*)(uintptr_t)regs.Esp;
+#else
+#error Need a way to get the stack pointer for another thread on this platform
+#endif
+}
+
+static inline void* otherThreadStackBase(const PlatformThreadRegisters& regs, Collector::Thread* thread)
+{
+#if PLATFORM(DARWIN)
+  (void)regs;
+  return pthrad_get_stackaddr_np(thread->posixThread);
+// end PLATFORM(DARWIN);
+#elif PLATFORM(X86) && PLATFORM(WIN_OS)
+  LDT_ENTRY desc;
+  NT_TIB* tib;
+  GetThreadSelectorEntry(thread->platformThread.handle, regs.SegFs, &desc);
+  tib = (NT_TIB*)(uintptr_t)(desc.BaseLow | desc.HighWord.Bytes.BaseMid << 16 | desc.HighWord.Bytes.BaseHi << 24);
+  ASSERT(tib == tib->Self);
+  return tib->StackBase;
+#else
+#error Need a way to get the stack pointer for another thread on this platform
+#endif
+}
+
+void Collector::markOtherThreadConservatively(Thread* thread)
+{
+  suspendThread(thread->platformThread);
+
+  PlatformThreadRegisters regs;
+  size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
+
+  // mark the thread's registers
+  markStackObjectsConservatively((void*)&regs, (void*)((char*)&regs + regSize));
+  void* stackPointer = otherThreadStackPointer(regs);
+  void* stackBase = otherThreadStackBase(regs, thread);
+  markStackObjectsConservatively(stackPointer, stackBase);
+
+  resumeThread(thread->platformThread);
 }
 
 #endif
@@ -447,7 +592,7 @@ void Collector::markStackObjectsConservatively()
 
 #if USE(MULTIPLE_THREADS)
   for (Thread *thread = registeredThreads; thread != NULL; thread = thread->next) {
-    if (thread->posixThread != pthread_self()) {
+    if (!pthread_equal(thread->posixThread, pthread_self())) {
       markOtherThreadConservatively(thread);
     }
   }
@@ -464,8 +609,9 @@ static ProtectCountSet& protectedValues()
 
 void Collector::protect(JSValue *k)
 {
-    assert(k);
-    assert(JSLock::lockCount() > 0);
+    ASSERT(k);
+    ASSERT(JSLock::lockCount() > 0);
+    ASSERT(JSLock::currentThreadIsHoldingLock());
 
     if (JSImmediate::isImmediate(k))
       return;
@@ -475,8 +621,9 @@ void Collector::protect(JSValue *k)
 
 void Collector::unprotect(JSValue *k)
 {
-    assert(k);
-    assert(JSLock::lockCount() > 0);
+    ASSERT(k);
+    ASSERT(JSLock::lockCount() > 0);
+    ASSERT(JSLock::currentThreadIsHoldingLock());
 
     if (JSImmediate::isImmediate(k))
       return;
@@ -488,6 +635,7 @@ void Collector::collectOnMainThreadOnly(JSValue* value)
 {
     ASSERT(value);
     ASSERT(JSLock::lockCount() > 0);
+    ASSERT(JSLock::currentThreadIsHoldingLock());
 
     if (JSImmediate::isImmediate(value))
       return;
@@ -511,7 +659,7 @@ void Collector::markProtectedObjects()
 void Collector::markMainThreadOnlyObjects()
 {
 #if USE(MULTIPLE_THREADS)
-    ASSERT(!pthread_main_np());
+    ASSERT(!onMainThread());
 #endif
 
     // Optimization for clients that never register "main thread only" objects.
@@ -562,14 +710,16 @@ void Collector::markMainThreadOnlyObjects()
 
 bool Collector::collect()
 {
-  assert(JSLock::lockCount() > 0);
+  ASSERT(JSLock::lockCount() > 0);
+  ASSERT(JSLock::currentThreadIsHoldingLock());
+
 
 #ifndef NDEBUG
   GCLock lock;
 #endif
   
 #if USE(MULTIPLE_THREADS)
-    bool currentThreadIsMainThread = pthread_main_np();
+    bool currentThreadIsMainThread = onMainThread();
 #else
     bool currentThreadIsMainThread = true;
 #endif
index 43adee00dc6840e527ee796df7ba17c01849aaf7..e2a3b90b7d15d38480f34ccc6d9ed1d08f14de6d 100644 (file)
@@ -58,6 +58,8 @@ namespace KJS {
     class Thread;
     static void registerThread();
     
+    static void registerAsMainThread();
+
   private:
     Collector();
 
index eb622a688aecbab063e765ac1d306daff6e2b295..91f2b783e84c41e696ef79a1fc645ec54ab5d94c 100644 (file)
@@ -66,6 +66,9 @@
 #include "FastMalloc.h"
 
 #include "Assertions.h"
+#if USE(MULTIPLE_THREADS)
+#include <pthread.h>
+#endif
 
 #ifndef USE_SYSTEM_MALLOC
 #ifndef NDEBUG
@@ -159,11 +162,9 @@ void *fastRealloc(void* p, size_t n)
     return realloc(p, n);
 }
 
-#if !PLATFORM(WIN_OS)
 void fastMallocSetIsMultiThreaded() 
 {
 }
-#endif
 
 } // namespace WTF
 
index 7003e7109c8229952b93f3177974f7c8c46dab1d..c40b35311f4148e56b622c557c106b120316a4c3 100644 (file)
 #ifndef WTF_FastMallocInternal_h
 #define WTF_FastMallocInternal_h
 
-#if !PLATFORM(WIN_OS)
-
-#include <pthread.h>
-
 namespace WTF {
     // Clients must call this function before allocating memory on a secondary thread.
     void fastMallocSetIsMultiThreaded();
 }
 
-#endif
-
 #endif //  WTF_FastMallocInternal_h
index 6829da04c8d6ca6b70022837212cfdc481841843..36dc00d5cc8fd72bd5fac1a81c3f66d576117650 100644 (file)
 #endif
 
 /* multiple threads only supported on Mac for now */
-#if PLATFORM(MAC)
+#if PLATFORM(MAC) || PLATFORM(WIN)
 #define WTF_USE_MULTIPLE_THREADS 1
 #endif