📄 collector.cpp
字号:
// FIXME: Consider doing this in NDEBUG builds too (see comment above). heap.operationInProgress = NoOperation;#endif return newCell;}void* Heap::allocate(size_t s){ return heapAllocate<PrimaryHeap>(s);}void* Heap::allocateNumber(size_t s){ return heapAllocate<NumberHeap>(s);}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 static_cast<void*>(pTib->StackBase);#elif PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC) PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); return reinterpret_cast<void*>(pTib->StackBase);#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(GCC) // offset 0x18 from the FS segment register gives a pointer to // the thread information block for the current thread NT_TIB* pTib; asm ( "movl %%fs:0x18, %0\n" : "=r" (pTib) ); return static_cast<void*>(pTib->StackBase);#elif PLATFORM(SOLARIS) stack_t s; thr_stksegment(&s); return s.ss_sp;#elif PLATFORM(OPENBSD) pthread_t thread = pthread_self(); stack_t stack; pthread_stackseg_np(thread, &stack); return stack.ss_sp;#elif PLATFORM(UNIX) static void* stackBase = 0; static size_t stackSize = 0; static pthread_t stackThread; pthread_t thread = pthread_self(); if (stackBase == 0 || thread != stackThread) { pthread_attr_t sattr; pthread_attr_init(&sattr);#if HAVE(PTHREAD_NP_H) || PLATFORM(NETBSD) // 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 int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize); (void)rc; // FIXME: Deal with error code somehow? Seems fatal. ASSERT(stackBase); pthread_attr_destroy(&sattr); stackThread = thread; } return static_cast<char*>(stackBase) + stackSize;#elif PLATFORM(SYMBIAN) static void* stackBase = 0; if (stackBase == 0) { TThreadStackInfo info; RThread thread; thread.StackInfo(info); stackBase = (void*)info.iBase; } return (void*)stackBase;#else#error Need a way to get the stack base on this platform#endif}#if ENABLE(JSC_MULTIPLE_THREADS)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}void Heap::makeUsableFromMultipleThreads(){ if (m_currentThreadRegistrar) return; int error = pthread_key_create(&m_currentThreadRegistrar, unregisterThread); if (error) CRASH();}void Heap::registerThread(){ if (!m_currentThreadRegistrar || pthread_getspecific(m_currentThreadRegistrar)) return; pthread_setspecific(m_currentThreadRegistrar, this); Heap::Thread* thread = new Heap::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase()); MutexLocker lock(m_registeredThreadsMutex); thread->next = m_registeredThreads; m_registeredThreads = thread;}void Heap::unregisterThread(void* p){ if (p) static_cast<Heap*>(p)->unregisterThread();}void Heap::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 { Heap::Thread* last = m_registeredThreads; Heap::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; }}#else // ENABLE(JSC_MULTIPLE_THREADS)void Heap::registerThread(){}#endif#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) & (sizeof(char*) - 1)) == 0)// cell size needs to be a power of two for this to be valid#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0)void Heap::markConservatively(void* start, void* end){ if (start > end) { void* tmp = start; start = end; end = tmp; } ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000); ASSERT(IS_POINTER_ALIGNED(start)); ASSERT(IS_POINTER_ALIGNED(end)); char** p = static_cast<char**>(start); char** e = static_cast<char**>(end); size_t usedPrimaryBlocks = primaryHeap.usedBlocks; size_t usedNumberBlocks = numberHeap.usedBlocks; CollectorBlock** primaryBlocks = primaryHeap.blocks; CollectorBlock** numberBlocks = numberHeap.blocks; const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1); while (p != e) { char* x = *p++; if (IS_HALF_CELL_ALIGNED(x) && x) { uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x); xAsBits &= CELL_ALIGN_MASK; uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK; CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset); // Mark the the number heap, we can mark these Cells directly to avoid the virtual call cost for (size_t block = 0; block < usedNumberBlocks; block++) { if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { Heap::markCell(reinterpret_cast<JSCell*>(xAsBits)); goto endMarkLoop; } } // Mark the primary heap for (size_t block = 0; block < usedPrimaryBlocks; block++) { if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) { if (reinterpret_cast<CollectorCell*>(xAsBits)->u.freeCell.zeroIfFree != 0) { JSCell* imp = reinterpret_cast<JSCell*>(xAsBits); if (!imp->marked()) imp->mark(); } break; } } endMarkLoop: ; } }}void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal(){ void* dummy; void* stackPointer = &dummy; void* stackBase = currentThreadStackBase(); markConservatively(stackPointer, stackBase);}void Heap::markCurrentThreadConservatively(){ // setjmp forces volatile registers onto the stack jmp_buf registers;#if COMPILER(MSVC)#pragma warning(push)#pragma warning(disable: 4611)#endif setjmp(registers);#if COMPILER(MSVC)#pragma warning(pop)#endif markCurrentThreadConservativelyInternal();}#if ENABLE(JSC_MULTIPLE_THREADS)static inline void suspendThread(const PlatformThread& platformThread){#if PLATFORM(DARWIN) thread_suspend(platformThread);#elif PLATFORM(WIN_OS) SuspendThread(platformThread.handle);#else#error Need a way to suspend threads on this platform#endif}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 resume threads on this platform#endif}typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit#if PLATFORM(DARWIN)#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;#elif PLATFORM(ARM)typedef arm_thread_state_t PlatformThreadRegisters;#else#error Unknown Architecture#endif#elif PLATFORM(WIN_OS)&& PLATFORM(X86)typedef CONTEXT PlatformThreadRegisters;#else#error Need a thread register struct for this platform#endifstatic size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs){#if PLATFORM(DARWIN)#if PLATFORM(X86) unsigned user_count = sizeof(regs)/sizeof(int); thread_state_flavor_t flavor = i386_THREAD_STATE;#elif PLATFORM(X86_64) unsigned user_count = x86_THREAD_STATE64_COUNT; thread_state_flavor_t flavor = x86_THREAD_STATE64;#elif PLATFORM(PPC) unsigned user_count = PPC_THREAD_STATE_COUNT; thread_state_flavor_t flavor = PPC_THREAD_STATE;#elif PLATFORM(PPC64) unsigned user_count = PPC_THREAD_STATE64_COUNT; thread_state_flavor_t flavor = PPC_THREAD_STATE64;#elif PLATFORM(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 PLATFORM(DARWIN)#elif PLATFORM(WIN_OS) && PLATFORM(X86) regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; GetThreadContext(platformThread.handle, ®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 PLATFORM(DARWIN)#if __DARWIN_UNIX03#if PLATFORM(X86) return reinterpret_cast<void*>(regs.__esp);#elif PLATFORM(X86_64) return reinterpret_cast<void*>(regs.__rsp);#elif PLATFORM(PPC) || PLATFORM(PPC64) return reinterpret_cast<void*>(regs.__r1);#elif PLATFORM(ARM) return reinterpret_cast<void*>(regs.__sp);#else#error Unknown Architecture#endif#else // !__DARWIN_UNIX03#if PLATFORM(X86) return reinterpret_cast<void*>(regs.esp);#elif PLATFORM(X86_64) return reinterpret_cast<void*>(regs.rsp);#elif (PLATFORM(PPC) || PLATFORM(PPC64)) return reinterpret_cast<void*>(regs.r1);#else#error Unknown Architecture#endif#endif // __DARWIN_UNIX03// end PLATFORM(DARWIN)#elif PLATFORM(X86) && PLATFORM(WIN_OS) 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 Heap::markOtherThreadConservatively(Thread* thread)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -