diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-09-11 19:54:20 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-09-11 19:54:20 +0200 |
commit | 88a04ac016f57c2d78e714682445dff2e7db4ade (patch) | |
tree | a48ca81ee3b29953121308168db22532d5b57fe2 /Source/JavaScriptCore/heap/MarkStack.cpp | |
parent | 284837daa07b29d6a63a748544a90b1f5842ac5c (diff) | |
download | qtwebkit-88a04ac016f57c2d78e714682445dff2e7db4ade.tar.gz |
Imported WebKit commit 42d95198c30c2d1a94a5081181aad0b2be7c316c (http://svn.webkit.org/repository/webkit/trunk@128206)
This includes the rewrite of the configure part of the build system which should fix the QtQuick2 detection
and allow for further simplifications in the future
Diffstat (limited to 'Source/JavaScriptCore/heap/MarkStack.cpp')
-rw-r--r-- | Source/JavaScriptCore/heap/MarkStack.cpp | 398 |
1 files changed, 0 insertions, 398 deletions
diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp index 9a4a01f04..582439fd2 100644 --- a/Source/JavaScriptCore/heap/MarkStack.cpp +++ b/Source/JavaScriptCore/heap/MarkStack.cpp @@ -223,402 +223,4 @@ void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other, size_t idleThread append(other.removeLast()); } -MarkStack::MarkStack(GCThreadSharedData& shared) - : m_stack(shared.m_segmentAllocator) -#if !ASSERT_DISABLED - , m_isCheckingForDefaultMarkViolation(false) - , m_isDraining(false) -#endif - , m_visitCount(0) - , m_isInParallelMode(false) - , m_shared(shared) - , m_shouldHashConst(false) -{ -} - -MarkStack::~MarkStack() -{ - ASSERT(m_stack.isEmpty()); -} - -void MarkStack::setup() -{ - m_shared.m_shouldHashConst = m_shared.m_globalData->haveEnoughNewStringsToHashConst(); - m_shouldHashConst = m_shared.m_shouldHashConst; -#if ENABLE(PARALLEL_GC) - for (unsigned i = 0; i < m_shared.m_markingThreadsMarkStack.size(); ++i) - m_shared.m_markingThreadsMarkStack[i]->m_shouldHashConst = m_shared.m_shouldHashConst; -#endif -} - -void MarkStack::reset() -{ - m_visitCount = 0; - ASSERT(m_stack.isEmpty()); -#if ENABLE(PARALLEL_GC) - ASSERT(m_opaqueRoots.isEmpty()); // Should have merged by now. -#else - m_opaqueRoots.clear(); -#endif - if (m_shouldHashConst) { - m_uniqueStrings.clear(); - m_shouldHashConst = false; - } -} - -void MarkStack::append(ConservativeRoots& conservativeRoots) -{ - JSCell** roots = conservativeRoots.roots(); - size_t size = conservativeRoots.size(); - for (size_t i = 0; i < size; ++i) - internalAppend(roots[i]); -} - -ALWAYS_INLINE static void visitChildren(SlotVisitor& visitor, const JSCell* cell) -{ -#if ENABLE(SIMPLE_HEAP_PROFILING) - m_visitedTypeCounts.count(cell); -#endif - - ASSERT(Heap::isMarked(cell)); - - if (isJSString(cell)) { - JSString::visitChildren(const_cast<JSCell*>(cell), visitor); - return; - } - - if (isJSFinalObject(cell)) { - JSFinalObject::visitChildren(const_cast<JSCell*>(cell), visitor); - return; - } - - if (isJSArray(cell)) { - JSArray::visitChildren(const_cast<JSCell*>(cell), visitor); - return; - } - - cell->methodTable()->visitChildren(const_cast<JSCell*>(cell), visitor); -} - -void SlotVisitor::donateKnownParallel() -{ - // NOTE: Because we re-try often, we can afford to be conservative, and - // assume that donating is not profitable. - - // Avoid locking when a thread reaches a dead end in the object graph. - if (m_stack.size() < 2) - return; - - // If there's already some shared work queued up, be conservative and assume - // that donating more is not profitable. - if (m_shared.m_sharedMarkStack.size()) - return; - - // If we're contending on the lock, be conservative and assume that another - // thread is already donating. - MutexTryLocker locker(m_shared.m_markingLock); - if (!locker.locked()) - return; - - // Otherwise, assume that a thread will go idle soon, and donate. - m_stack.donateSomeCellsTo(m_shared.m_sharedMarkStack); - - if (m_shared.m_numberOfActiveParallelMarkers < Options::numberOfGCMarkers()) - m_shared.m_markingCondition.broadcast(); -} - -void SlotVisitor::drain() -{ - ASSERT(m_isInParallelMode); - -#if ENABLE(PARALLEL_GC) - if (Options::numberOfGCMarkers() > 1) { - while (!m_stack.isEmpty()) { - m_stack.refill(); - for (unsigned countdown = Options::minimumNumberOfScansBetweenRebalance(); m_stack.canRemoveLast() && countdown--;) - visitChildren(*this, m_stack.removeLast()); - donateKnownParallel(); - } - - mergeOpaqueRootsIfNecessary(); - return; - } -#endif - - while (!m_stack.isEmpty()) { - m_stack.refill(); - while (m_stack.canRemoveLast()) - visitChildren(*this, m_stack.removeLast()); - } -} - -void SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode) -{ - ASSERT(m_isInParallelMode); - - ASSERT(Options::numberOfGCMarkers()); - - bool shouldBeParallel; - -#if ENABLE(PARALLEL_GC) - shouldBeParallel = Options::numberOfGCMarkers() > 1; -#else - ASSERT(Options::numberOfGCMarkers() == 1); - shouldBeParallel = false; -#endif - - if (!shouldBeParallel) { - // This call should be a no-op. - ASSERT_UNUSED(sharedDrainMode, sharedDrainMode == MasterDrain); - ASSERT(m_stack.isEmpty()); - ASSERT(m_shared.m_sharedMarkStack.isEmpty()); - return; - } - -#if ENABLE(PARALLEL_GC) - { - MutexLocker locker(m_shared.m_markingLock); - m_shared.m_numberOfActiveParallelMarkers++; - } - while (true) { - { - MutexLocker locker(m_shared.m_markingLock); - m_shared.m_numberOfActiveParallelMarkers--; - - // How we wait differs depending on drain mode. - if (sharedDrainMode == MasterDrain) { - // Wait until either termination is reached, or until there is some work - // for us to do. - while (true) { - // Did we reach termination? - if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty()) { - // Let any sleeping slaves know it's time for them to give their private CopiedBlocks back - m_shared.m_markingCondition.broadcast(); - return; - } - - // Is there work to be done? - if (!m_shared.m_sharedMarkStack.isEmpty()) - break; - - // Otherwise wait. - m_shared.m_markingCondition.wait(m_shared.m_markingLock); - } - } else { - ASSERT(sharedDrainMode == SlaveDrain); - - // Did we detect termination? If so, let the master know. - if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty()) - m_shared.m_markingCondition.broadcast(); - - while (m_shared.m_sharedMarkStack.isEmpty() && !m_shared.m_parallelMarkersShouldExit) { - if (!m_shared.m_numberOfActiveParallelMarkers && m_shared.m_sharedMarkStack.isEmpty()) - doneCopying(); - m_shared.m_markingCondition.wait(m_shared.m_markingLock); - } - - // Is the VM exiting? If so, exit this thread. - if (m_shared.m_parallelMarkersShouldExit) { - doneCopying(); - return; - } - } - - size_t idleThreadCount = Options::numberOfGCMarkers() - m_shared.m_numberOfActiveParallelMarkers; - m_stack.stealSomeCellsFrom(m_shared.m_sharedMarkStack, idleThreadCount); - m_shared.m_numberOfActiveParallelMarkers++; - } - - drain(); - } -#endif -} - -void MarkStack::mergeOpaqueRoots() -{ - ASSERT(!m_opaqueRoots.isEmpty()); // Should only be called when opaque roots are non-empty. - { - MutexLocker locker(m_shared.m_opaqueRootsLock); - HashSet<void*>::iterator begin = m_opaqueRoots.begin(); - HashSet<void*>::iterator end = m_opaqueRoots.end(); - for (HashSet<void*>::iterator iter = begin; iter != end; ++iter) - m_shared.m_opaqueRoots.add(*iter); - } - m_opaqueRoots.clear(); -} - -void SlotVisitor::startCopying() -{ - ASSERT(!m_copiedAllocator.isValid()); -} - -void* SlotVisitor::allocateNewSpaceSlow(size_t bytes) -{ - m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock()); - m_copiedAllocator.setCurrentBlock(m_shared.m_copiedSpace->allocateBlockForCopyingPhase()); - - void* result = 0; - CheckedBoolean didSucceed = m_copiedAllocator.tryAllocate(bytes, &result); - ASSERT(didSucceed); - return result; -} - -void* SlotVisitor::allocateNewSpaceOrPin(void* ptr, size_t bytes) -{ - if (!checkIfShouldCopyAndPinOtherwise(ptr, bytes)) - return 0; - - return allocateNewSpace(bytes); -} - -ALWAYS_INLINE bool JSString::tryHashConstLock() -{ -#if ENABLE(PARALLEL_GC) - unsigned currentFlags = m_flags; - - if (currentFlags & HashConstLock) - return false; - - unsigned newFlags = currentFlags | HashConstLock; - - if (!WTF::weakCompareAndSwap(&m_flags, currentFlags, newFlags)) - return false; - - WTF::memoryBarrierAfterLock(); - return true; -#else - if (isHashConstSingleton()) - return false; - - m_flags |= HashConstLock; - - return true; -#endif -} - -ALWAYS_INLINE void JSString::releaseHashConstLock() -{ -#if ENABLE(PARALLEL_GC) - WTF::memoryBarrierBeforeUnlock(); -#endif - m_flags &= ~HashConstLock; -} - -ALWAYS_INLINE bool JSString::shouldTryHashConst() -{ - return ((length() > 1) && !isRope() && !isHashConstSingleton()); -} - -ALWAYS_INLINE void MarkStack::internalAppend(JSValue* slot) -{ - // This internalAppend is only intended for visits to object and array backing stores. - // as it can change the JSValue pointed to be the argument when the original JSValue - // is a string that contains the same contents as another string. - - ASSERT(slot); - JSValue value = *slot; - ASSERT(value); - if (!value.isCell()) - return; - - JSCell* cell = value.asCell(); - if (!cell) - return; - - if (m_shouldHashConst && cell->isString()) { - JSString* string = jsCast<JSString*>(cell); - if (string->shouldTryHashConst() && string->tryHashConstLock()) { - UniqueStringMap::AddResult addResult = m_uniqueStrings.add(string->string().impl(), value); - if (addResult.isNewEntry) - string->setHashConstSingleton(); - else { - JSValue existingJSValue = addResult.iterator->second; - if (value != existingJSValue) - jsCast<JSString*>(existingJSValue.asCell())->clearHashConstSingleton(); - *slot = existingJSValue; - string->releaseHashConstLock(); - return; - } - string->releaseHashConstLock(); - } - } - - internalAppend(cell); -} - -void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsigned length) -{ - void* oldPtr = *ptr; - void* newPtr = allocateNewSpaceOrPin(oldPtr, bytes); - if (newPtr) { - size_t jsValuesOffset = static_cast<size_t>(reinterpret_cast<char*>(values) - static_cast<char*>(oldPtr)); - - JSValue* newValues = reinterpret_cast_ptr<JSValue*>(static_cast<char*>(newPtr) + jsValuesOffset); - for (unsigned i = 0; i < length; i++) { - JSValue& value = values[i]; - newValues[i] = value; - if (!value) - continue; - internalAppend(&newValues[i]); - } - - memcpy(newPtr, oldPtr, jsValuesOffset); - *ptr = newPtr; - } else - append(values, length); -} - -void SlotVisitor::doneCopying() -{ - if (!m_copiedAllocator.isValid()) - return; - - m_shared.m_copiedSpace->doneFillingBlock(m_copiedAllocator.resetCurrentBlock()); -} - -void SlotVisitor::harvestWeakReferences() -{ - for (WeakReferenceHarvester* current = m_shared.m_weakReferenceHarvesters.head(); current; current = current->next()) - current->visitWeakReferences(*this); -} - -void SlotVisitor::finalizeUnconditionalFinalizers() -{ - while (m_shared.m_unconditionalFinalizers.hasNext()) - m_shared.m_unconditionalFinalizers.removeNext()->finalizeUnconditionally(); -} - -#if ENABLE(GC_VALIDATION) -void MarkStack::validate(JSCell* cell) -{ - if (!cell) { - dataLog("cell is NULL\n"); - CRASH(); - } - - if (!cell->structure()) { - dataLog("cell at %p has a null structure\n" , cell); - CRASH(); - } - - // Both the cell's structure, and the cell's structure's structure should be the Structure Structure. - // I hate this sentence. - if (cell->structure()->structure()->JSCell::classInfo() != cell->structure()->JSCell::classInfo()) { - const char* parentClassName = 0; - const char* ourClassName = 0; - if (cell->structure()->structure() && cell->structure()->structure()->JSCell::classInfo()) - parentClassName = cell->structure()->structure()->JSCell::classInfo()->className; - if (cell->structure()->JSCell::classInfo()) - ourClassName = cell->structure()->JSCell::classInfo()->className; - dataLog("parent structure (%p <%s>) of cell at %p doesn't match cell's structure (%p <%s>)\n", - cell->structure()->structure(), parentClassName, cell, cell->structure(), ourClassName); - CRASH(); - } -} -#else -void MarkStack::validate(JSCell*) -{ -} -#endif - } // namespace JSC |