diff options
author | Ben Murdoch <benm@google.com> | 2011-06-02 12:07:03 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-10 10:47:21 +0100 |
commit | 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch) | |
tree | e4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/JavaScriptCore/runtime/Heap.cpp | |
parent | 87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff) | |
download | external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2 |
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Source/JavaScriptCore/runtime/Heap.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/Heap.cpp | 408 |
1 files changed, 0 insertions, 408 deletions
diff --git a/Source/JavaScriptCore/runtime/Heap.cpp b/Source/JavaScriptCore/runtime/Heap.cpp deleted file mode 100644 index e3ef8bb..0000000 --- a/Source/JavaScriptCore/runtime/Heap.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/* - * 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 "Heap.h" - -#include "CodeBlock.h" -#include "ConservativeSet.h" -#include "GCActivityCallback.h" -#include "Interpreter.h" -#include "JSGlobalData.h" -#include "JSGlobalObject.h" -#include "JSLock.h" -#include "JSONObject.h" -#include "Tracing.h" -#include <algorithm> - -#define COLLECT_ON_EVERY_SLOW_ALLOCATION 0 - -using namespace std; - -namespace JSC { - -const size_t minBytesPerCycle = 512 * 1024; - -Heap::Heap(JSGlobalData* globalData) - : m_operationInProgress(NoOperation) - , m_markedSpace(globalData) - , m_markListSet(0) - , m_activityCallback(DefaultGCActivityCallback::create(this)) - , m_globalData(globalData) - , m_machineThreads(this) - , m_markStack(globalData->jsArrayVPtr) - , m_handleHeap(globalData) - , m_extraCost(0) -{ - m_markedSpace.setHighWaterMark(minBytesPerCycle); - (*m_activityCallback)(); -} - -Heap::~Heap() -{ - // The destroy function must already have been called, so assert this. - ASSERT(!m_globalData); -} - -void Heap::destroy() -{ - JSLock lock(SilenceAssertionsOnly); - - if (!m_globalData) - return; - - ASSERT(!m_globalData->dynamicGlobalObject); - ASSERT(m_operationInProgress == NoOperation); - - // The global object is not GC protected at this point, so sweeping may delete it - // (and thus the global data) before other objects that may use the global data. - RefPtr<JSGlobalData> protect(m_globalData); - -#if ENABLE(JIT) - m_globalData->jitStubs->clearHostFunctionStubs(); -#endif - - delete m_markListSet; - m_markListSet = 0; - m_markedSpace.clearMarks(); - m_handleHeap.clearWeakPointers(); - m_markedSpace.destroy(); - - m_globalData = 0; -} - -void Heap::reportExtraMemoryCostSlowCase(size_t cost) -{ - // Our frequency of garbage collection tries to balance memory use against speed - // by collecting based on the number of newly created values. However, for values - // that hold on to a great deal of memory that's not in the form of other JS values, - // that is not good enough - in some cases a lot of those objects can pile up and - // use crazy amounts of memory without a GC happening. So we track these extra - // memory costs. Only unusually large objects are noted, and we only keep track - // of this extra cost until the next GC. In garbage collected languages, most values - // are either very short lived temporaries, or have extremely long lifetimes. So - // if a large value survives one garbage collection, there is not much point to - // collecting more frequently as long as it stays alive. - - if (m_extraCost > maxExtraCost && m_extraCost > m_markedSpace.highWaterMark() / 2) - collectAllGarbage(); - m_extraCost += cost; -} - -void* Heap::allocateSlowCase(size_t bytes) -{ - ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); - ASSERT(JSLock::lockCount() > 0); - ASSERT(JSLock::currentThreadIsHoldingLock()); - ASSERT(bytes <= MarkedSpace::maxCellSize); - ASSERT(m_operationInProgress == NoOperation); - -#if COLLECT_ON_EVERY_SLOW_ALLOCATION - collectAllGarbage(); - ASSERT(m_operationInProgress == NoOperation); -#endif - - reset(DoNotSweep); - - m_operationInProgress = Allocation; - void* result = m_markedSpace.allocate(bytes); - m_operationInProgress = NoOperation; - - ASSERT(result); - return result; -} - -void Heap::protect(JSValue k) -{ - ASSERT(k); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); - - if (!k.isCell()) - return; - - m_protectedValues.add(k.asCell()); -} - -bool Heap::unprotect(JSValue k) -{ - ASSERT(k); - ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); - - if (!k.isCell()) - return false; - - return m_protectedValues.remove(k.asCell()); -} - -void Heap::markProtectedObjects(HeapRootMarker& heapRootMarker) -{ - ProtectCountSet::iterator end = m_protectedValues.end(); - for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) - heapRootMarker.mark(&it->first); -} - -void Heap::pushTempSortVector(Vector<ValueStringPair>* tempVector) -{ - m_tempSortingVectors.append(tempVector); -} - -void Heap::popTempSortVector(Vector<ValueStringPair>* tempVector) -{ - ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last()); - m_tempSortingVectors.removeLast(); -} - -void Heap::markTempSortVectors(HeapRootMarker& heapRootMarker) -{ - typedef Vector<Vector<ValueStringPair>* > VectorOfValueStringVectors; - - VectorOfValueStringVectors::iterator end = m_tempSortingVectors.end(); - for (VectorOfValueStringVectors::iterator it = m_tempSortingVectors.begin(); it != end; ++it) { - Vector<ValueStringPair>* tempSortingVector = *it; - - Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end(); - for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt) { - if (vectorIt->first) - heapRootMarker.mark(&vectorIt->first); - } - } -} - -inline RegisterFile& Heap::registerFile() -{ - return m_globalData->interpreter->registerFile(); -} - -void Heap::markRoots() -{ -#ifndef NDEBUG - if (m_globalData->isSharedInstance()) { - ASSERT(JSLock::lockCount() > 0); - ASSERT(JSLock::currentThreadIsHoldingLock()); - } -#endif - - void* dummy; - - ASSERT(m_operationInProgress == NoOperation); - if (m_operationInProgress != NoOperation) - CRASH(); - - m_operationInProgress = Collection; - - MarkStack& markStack = m_markStack; - HeapRootMarker heapRootMarker(markStack); - - // We gather conservative roots before clearing mark bits because - // conservative gathering uses the mark bits from our last mark pass to - // determine whether a reference is valid. - ConservativeRoots machineThreadRoots(this); - m_machineThreads.gatherConservativeRoots(machineThreadRoots, &dummy); - - ConservativeRoots registerFileRoots(this); - registerFile().gatherConservativeRoots(registerFileRoots); - - m_markedSpace.clearMarks(); - - markStack.append(machineThreadRoots); - markStack.drain(); - - markStack.append(registerFileRoots); - markStack.drain(); - - markProtectedObjects(heapRootMarker); - markStack.drain(); - - markTempSortVectors(heapRootMarker); - markStack.drain(); - - if (m_markListSet && m_markListSet->size()) - MarkedArgumentBuffer::markLists(heapRootMarker, *m_markListSet); - if (m_globalData->exception) - heapRootMarker.mark(&m_globalData->exception); - markStack.drain(); - - m_handleHeap.markStrongHandles(heapRootMarker); - m_handleStack.mark(heapRootMarker); - - // Mark the small strings cache last, since it will clear itself if nothing - // else has marked it. - m_globalData->smallStrings.markChildren(heapRootMarker); - - markStack.drain(); - markStack.compact(); - - m_handleHeap.updateAfterMark(); - - m_operationInProgress = NoOperation; -} - -size_t Heap::objectCount() const -{ - return m_markedSpace.objectCount(); -} - -size_t Heap::size() const -{ - return m_markedSpace.size(); -} - -size_t Heap::capacity() const -{ - return m_markedSpace.capacity(); -} - -size_t Heap::globalObjectCount() -{ - return m_globalData->globalObjectCount; -} - -size_t Heap::protectedGlobalObjectCount() -{ - size_t count = m_handleHeap.protectedGlobalObjectCount(); - - ProtectCountSet::iterator end = m_protectedValues.end(); - for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) { - if (it->first->isObject() && asObject(it->first)->isGlobalObject()) - count++; - } - - return count; -} - -size_t Heap::protectedObjectCount() -{ - return m_protectedValues.size(); -} - -class TypeCounter { -public: - TypeCounter(); - void operator()(JSCell*); - PassOwnPtr<TypeCountSet> take(); - -private: - const char* typeName(JSCell*); - OwnPtr<TypeCountSet> m_typeCountSet; -}; - -inline TypeCounter::TypeCounter() - : m_typeCountSet(new TypeCountSet) -{ -} - -inline const char* TypeCounter::typeName(JSCell* cell) -{ - if (cell->isString()) - return "string"; - if (cell->isGetterSetter()) - return "Getter-Setter"; - if (cell->isAPIValueWrapper()) - return "API wrapper"; - if (cell->isPropertyNameIterator()) - return "For-in iterator"; - if (!cell->isObject()) - return "[empty cell]"; - const ClassInfo* info = cell->classInfo(); - return info ? info->className : "Object"; -} - -inline void TypeCounter::operator()(JSCell* cell) -{ - m_typeCountSet->add(typeName(cell)); -} - -inline PassOwnPtr<TypeCountSet> TypeCounter::take() -{ - return m_typeCountSet.release(); -} - -PassOwnPtr<TypeCountSet> Heap::protectedObjectTypeCounts() -{ - TypeCounter typeCounter; - - ProtectCountSet::iterator end = m_protectedValues.end(); - for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) - typeCounter(it->first); - - return typeCounter.take(); -} - -PassOwnPtr<TypeCountSet> Heap::objectTypeCounts() -{ - TypeCounter typeCounter; - forEach(typeCounter); - return typeCounter.take(); -} - -bool Heap::isBusy() -{ - return m_operationInProgress != NoOperation; -} - -void Heap::collectAllGarbage() -{ - reset(DoSweep); -} - -void Heap::reset(SweepToggle sweepToggle) -{ - ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); - JAVASCRIPTCORE_GC_BEGIN(); - - markRoots(); - - JAVASCRIPTCORE_GC_MARKED(); - - m_markedSpace.reset(); - m_extraCost = 0; - -#if ENABLE(JSC_ZOMBIES) - sweepToggle = DoSweep; -#endif - - if (sweepToggle == DoSweep) { - m_markedSpace.sweep(); - m_markedSpace.shrink(); - } - - // To avoid pathological GC churn in large heaps, we set the allocation high - // water mark to be proportional to the current size of the heap. The exact - // proportion is a bit arbitrary. A 2X multiplier gives a 1:1 (heap size : - // new bytes allocated) proportion, and seems to work well in benchmarks. - size_t proportionalBytes = 2 * m_markedSpace.size(); - m_markedSpace.setHighWaterMark(max(proportionalBytes, minBytesPerCycle)); - - JAVASCRIPTCORE_GC_END(); - - (*m_activityCallback)(); -} - -void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback) -{ - m_activityCallback = activityCallback; -} - -GCActivityCallback* Heap::activityCallback() -{ - return m_activityCallback.get(); -} - -} // namespace JSC |