diff options
author | Ben Murdoch <benm@google.com> | 2011-05-13 16:23:25 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-05-16 11:35:02 +0100 |
commit | 65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch) | |
tree | f478babb801e720de7bfaee23443ffe029f58731 /Source/JavaScriptCore/runtime/MachineStackMarker.cpp | |
parent | 47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff) | |
download | external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.zip external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.gz external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.bz2 |
Merge WebKit at r75993: Initial merge by git.
Change-Id: I602bbdc3974787a3b0450456a30a7868286921c3
Diffstat (limited to 'Source/JavaScriptCore/runtime/MachineStackMarker.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/MachineStackMarker.cpp | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/MachineStackMarker.cpp b/Source/JavaScriptCore/runtime/MachineStackMarker.cpp new file mode 100644 index 0000000..b4a1936 --- /dev/null +++ b/Source/JavaScriptCore/runtime/MachineStackMarker.cpp @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include "MachineStackMarker.h" + +#include "Heap.h" +#include "JSArray.h" +#include "JSGlobalData.h" +#include <setjmp.h> +#include <stdlib.h> + +#if OS(DARWIN) + +#include <mach/mach_init.h> +#include <mach/mach_port.h> +#include <mach/task.h> +#include <mach/thread_act.h> +#include <mach/vm_map.h> + +#elif OS(WINDOWS) + +#include <windows.h> +#include <malloc.h> + +#elif OS(HAIKU) + +#include <OS.h> + +#elif OS(UNIX) + +#include <stdlib.h> +#if !OS(HAIKU) +#include <sys/mman.h> +#endif +#include <unistd.h> + +#if OS(SOLARIS) +#include <thread.h> +#else +#include <pthread.h> +#endif + +#if HAVE(PTHREAD_NP_H) +#include <pthread_np.h> +#endif + +#if OS(QNX) +#include <fcntl.h> +#include <sys/procfs.h> +#include <stdio.h> +#include <errno.h> +#endif + +#endif + +namespace JSC { + +#if ENABLE(JSC_MULTIPLE_THREADS) + +#if OS(DARWIN) +typedef mach_port_t PlatformThread; +#elif OS(WINDOWS) +typedef HANDLE PlatformThread; +#endif + +class MachineStackMarker::Thread { +public: + Thread(pthread_t pthread, const PlatformThread& platThread, void* base) + : posixThread(pthread) + , platformThread(platThread) + , stackBase(base) + { + } + + Thread* next; + pthread_t posixThread; + PlatformThread platformThread; + void* stackBase; +}; + +#endif + +MachineStackMarker::MachineStackMarker(Heap* heap) + : m_heap(heap) +#if ENABLE(JSC_MULTIPLE_THREADS) + , m_registeredThreads(0) + , m_currentThreadRegistrar(0) +#endif +{ +} + +MachineStackMarker::~MachineStackMarker() +{ +#if ENABLE(JSC_MULTIPLE_THREADS) + if (m_currentThreadRegistrar) { + int error = pthread_key_delete(m_currentThreadRegistrar); + ASSERT_UNUSED(error, !error); + } + + MutexLocker registeredThreadsLock(m_registeredThreadsMutex); + for (Thread* t = m_registeredThreads; t;) { + Thread* next = t->next; + delete t; + t = next; + } +#endif +} + +#if ENABLE(JSC_MULTIPLE_THREADS) + +static inline PlatformThread getCurrentPlatformThread() +{ +#if OS(DARWIN) + return pthread_mach_thread_np(pthread_self()); +#elif OS(WINDOWS) + return pthread_getw32threadhandle_np(pthread_self()); +#endif +} + +void MachineStackMarker::makeUsableFromMultipleThreads() +{ + if (m_currentThreadRegistrar) + return; + + int error = pthread_key_create(&m_currentThreadRegistrar, unregisterThread); + if (error) + CRASH(); +} + +void MachineStackMarker::registerThread() +{ + ASSERT(!m_heap->globalData()->exclusiveThread || m_heap->globalData()->exclusiveThread == currentThread()); + + if (!m_currentThreadRegistrar || pthread_getspecific(m_currentThreadRegistrar)) + return; + + pthread_setspecific(m_currentThreadRegistrar, this); + Thread* thread = new Thread(pthread_self(), getCurrentPlatformThread(), m_heap->globalData()->stack().origin()); + + MutexLocker lock(m_registeredThreadsMutex); + + thread->next = m_registeredThreads; + m_registeredThreads = thread; +} + +void MachineStackMarker::unregisterThread(void* p) +{ + if (p) + static_cast<MachineStackMarker*>(p)->unregisterThread(); +} + +void MachineStackMarker::unregisterThread() +{ + pthread_t currentPosixThread = pthread_self(); + + MutexLocker lock(m_registeredThreadsMutex); + + if (pthread_equal(currentPosixThread, m_registeredThreads->posixThread)) { + Thread* t = m_registeredThreads; + m_registeredThreads = m_registeredThreads->next; + delete t; + } else { + Thread* last = m_registeredThreads; + Thread* t; + for (t = m_registeredThreads->next; t; t = t->next) { + if (pthread_equal(t->posixThread, currentPosixThread)) { + last->next = t->next; + break; + } + last = t; + } + ASSERT(t); // If t is NULL, we never found ourselves in the list. + delete t; + } +} + +#endif + +void NEVER_INLINE MachineStackMarker::markCurrentThreadConservativelyInternal(MarkStack& markStack) +{ + m_heap->markConservatively(markStack, m_heap->globalData()->stack().current(), m_heap->globalData()->stack().origin()); + markStack.drain(); +} + +#if COMPILER(GCC) +#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*)))) +#else +#define REGISTER_BUFFER_ALIGNMENT +#endif + +void MachineStackMarker::markCurrentThreadConservatively(MarkStack& markStack) +{ + // setjmp forces volatile registers onto the stack + jmp_buf registers REGISTER_BUFFER_ALIGNMENT; +#if COMPILER(MSVC) +#pragma warning(push) +#pragma warning(disable: 4611) +#endif + setjmp(registers); +#if COMPILER(MSVC) +#pragma warning(pop) +#endif + + markCurrentThreadConservativelyInternal(markStack); +} + +#if ENABLE(JSC_MULTIPLE_THREADS) + +static inline void suspendThread(const PlatformThread& platformThread) +{ +#if OS(DARWIN) + thread_suspend(platformThread); +#elif OS(WINDOWS) + SuspendThread(platformThread); +#else +#error Need a way to suspend threads on this platform +#endif +} + +static inline void resumeThread(const PlatformThread& platformThread) +{ +#if OS(DARWIN) + thread_resume(platformThread); +#elif OS(WINDOWS) + ResumeThread(platformThread); +#else +#error Need a way to resume threads on this platform +#endif +} + +typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit + +#if OS(DARWIN) + +#if CPU(X86) +typedef i386_thread_state_t PlatformThreadRegisters; +#elif CPU(X86_64) +typedef x86_thread_state64_t PlatformThreadRegisters; +#elif CPU(PPC) +typedef ppc_thread_state_t PlatformThreadRegisters; +#elif CPU(PPC64) +typedef ppc_thread_state64_t PlatformThreadRegisters; +#elif CPU(ARM) +typedef arm_thread_state_t PlatformThreadRegisters; +#else +#error Unknown Architecture +#endif + +#elif OS(WINDOWS) && CPU(X86) +typedef CONTEXT PlatformThreadRegisters; +#else +#error Need a thread register struct for this platform +#endif + +static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs) +{ +#if OS(DARWIN) + +#if CPU(X86) + unsigned user_count = sizeof(regs)/sizeof(int); + thread_state_flavor_t flavor = i386_THREAD_STATE; +#elif CPU(X86_64) + unsigned user_count = x86_THREAD_STATE64_COUNT; + thread_state_flavor_t flavor = x86_THREAD_STATE64; +#elif CPU(PPC) + unsigned user_count = PPC_THREAD_STATE_COUNT; + thread_state_flavor_t flavor = PPC_THREAD_STATE; +#elif CPU(PPC64) + unsigned user_count = PPC_THREAD_STATE64_COUNT; + thread_state_flavor_t flavor = PPC_THREAD_STATE64; +#elif CPU(ARM) + unsigned user_count = ARM_THREAD_STATE_COUNT; + thread_state_flavor_t flavor = ARM_THREAD_STATE; +#else +#error Unknown Architecture +#endif + + kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)®s, &user_count); + if (result != KERN_SUCCESS) { + WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, + "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result); + CRASH(); + } + return user_count * sizeof(usword_t); +// end OS(DARWIN) + +#elif OS(WINDOWS) && CPU(X86) + regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; + GetThreadContext(platformThread, ®s); + return sizeof(CONTEXT); +#else +#error Need a way to get thread registers on this platform +#endif +} + +static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs) +{ +#if OS(DARWIN) + +#if __DARWIN_UNIX03 + +#if CPU(X86) + return reinterpret_cast<void*>(regs.__esp); +#elif CPU(X86_64) + return reinterpret_cast<void*>(regs.__rsp); +#elif CPU(PPC) || CPU(PPC64) + return reinterpret_cast<void*>(regs.__r1); +#elif CPU(ARM) + return reinterpret_cast<void*>(regs.__sp); +#else +#error Unknown Architecture +#endif + +#else // !__DARWIN_UNIX03 + +#if CPU(X86) + return reinterpret_cast<void*>(regs.esp); +#elif CPU(X86_64) + return reinterpret_cast<void*>(regs.rsp); +#elif CPU(PPC) || CPU(PPC64) + return reinterpret_cast<void*>(regs.r1); +#else +#error Unknown Architecture +#endif + +#endif // __DARWIN_UNIX03 + +// end OS(DARWIN) +#elif CPU(X86) && OS(WINDOWS) + return reinterpret_cast<void*>((uintptr_t) regs.Esp); +#else +#error Need a way to get the stack pointer for another thread on this platform +#endif +} + +void MachineStackMarker::markOtherThreadConservatively(MarkStack& markStack, Thread* thread) +{ + suspendThread(thread->platformThread); + + PlatformThreadRegisters regs; + size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); + + // mark the thread's registers + m_heap->markConservatively(markStack, static_cast<void*>(®s), static_cast<void*>(reinterpret_cast<char*>(®s) + regSize)); + markStack.drain(); + + void* stackPointer = otherThreadStackPointer(regs); + m_heap->markConservatively(markStack, stackPointer, thread->stackBase); + markStack.drain(); + + resumeThread(thread->platformThread); +} + +#endif + +void MachineStackMarker::markMachineStackConservatively(MarkStack& markStack) +{ + markCurrentThreadConservatively(markStack); + +#if ENABLE(JSC_MULTIPLE_THREADS) + + if (m_currentThreadRegistrar) { + + MutexLocker lock(m_registeredThreadsMutex); + +#ifndef NDEBUG + // Forbid malloc during the mark phase. Marking a thread suspends it, so + // a malloc inside markChildren() would risk a deadlock with a thread that had been + // suspended while holding the malloc lock. + fastMallocForbid(); +#endif + // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held, + // and since this is a shared heap, they are real locks. + for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { + if (!pthread_equal(thread->posixThread, pthread_self())) + markOtherThreadConservatively(markStack, thread); + } +#ifndef NDEBUG + fastMallocAllow(); +#endif + } +#endif +} + +} // namespace JSC |