diff options
Diffstat (limited to 'Source/JavaScriptCore/heap/HeapVerifier.cpp')
| -rw-r--r-- | Source/JavaScriptCore/heap/HeapVerifier.cpp | 290 |
1 files changed, 0 insertions, 290 deletions
diff --git a/Source/JavaScriptCore/heap/HeapVerifier.cpp b/Source/JavaScriptCore/heap/HeapVerifier.cpp deleted file mode 100644 index 0f4e28277..000000000 --- a/Source/JavaScriptCore/heap/HeapVerifier.cpp +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (C) 2014 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "HeapVerifier.h" - -#include "ButterflyInlines.h" -#include "CopiedSpaceInlines.h" -#include "HeapIterationScope.h" -#include "JSCInlines.h" -#include "JSObject.h" - -namespace JSC { - -HeapVerifier::HeapVerifier(Heap* heap, unsigned numberOfGCCyclesToRecord) - : m_heap(heap) - , m_currentCycle(0) - , m_numberOfCycles(numberOfGCCyclesToRecord) -{ - RELEASE_ASSERT(m_numberOfCycles > 0); - m_cycles = std::make_unique<GCCycle[]>(m_numberOfCycles); -} - -const char* HeapVerifier::collectionTypeName(HeapOperation type) -{ - switch (type) { - case NoOperation: - return "NoOperation"; - case AnyCollection: - return "AnyCollection"; - case Allocation: - return "Allocation"; - case EdenCollection: - return "EdenCollection"; - case FullCollection: - return "FullCollection"; - } - RELEASE_ASSERT_NOT_REACHED(); - return nullptr; // Silencing a compiler warning. -} - -const char* HeapVerifier::phaseName(HeapVerifier::Phase phase) -{ - switch (phase) { - case Phase::BeforeGC: - return "BeforeGC"; - case Phase::BeforeMarking: - return "BeforeMarking"; - case Phase::AfterMarking: - return "AfterMarking"; - case Phase::AfterGC: - return "AfterGC"; - } - RELEASE_ASSERT_NOT_REACHED(); - return nullptr; // Silencing a compiler warning. -} - -static void getButterflyDetails(JSObject* obj, void*& butterflyBase, size_t& butterflyCapacityInBytes, CopiedBlock*& butterflyBlock) -{ - Structure* structure = obj->structure(); - Butterfly* butterfly = obj->butterfly(); - butterflyBase = butterfly->base(structure); - butterflyBlock = CopiedSpace::blockFor(butterflyBase); - - size_t propertyCapacity = structure->outOfLineCapacity(); - size_t preCapacity; - size_t indexingPayloadSizeInBytes; - bool hasIndexingHeader = obj->hasIndexingHeader(); - if (UNLIKELY(hasIndexingHeader)) { - preCapacity = butterfly->indexingHeader()->preCapacity(structure); - indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure); - } else { - preCapacity = 0; - indexingPayloadSizeInBytes = 0; - } - butterflyCapacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); -} - -void HeapVerifier::initializeGCCycle() -{ - Heap* heap = m_heap; - incrementCycle(); - currentCycle().collectionType = heap->operationInProgress(); -} - -struct GatherLiveObjFunctor : MarkedBlock::CountFunctor { - GatherLiveObjFunctor(LiveObjectList& list) - : m_list(list) - { - ASSERT(!list.liveObjects.size()); - } - - inline void visit(JSCell* cell) - { - if (!cell->isObject()) - return; - LiveObjectData data(asObject(cell)); - m_list.liveObjects.append(data); - } - - IterationStatus operator()(JSCell* cell) - { - visit(cell); - return IterationStatus::Continue; - } - - LiveObjectList& m_list; -}; - -void HeapVerifier::gatherLiveObjects(HeapVerifier::Phase phase) -{ - Heap* heap = m_heap; - LiveObjectList& list = *liveObjectListForGathering(phase); - - HeapIterationScope iterationScope(*heap); - list.reset(); - GatherLiveObjFunctor functor(list); - heap->m_objectSpace.forEachLiveCell(iterationScope, functor); -} - -LiveObjectList* HeapVerifier::liveObjectListForGathering(HeapVerifier::Phase phase) -{ - switch (phase) { - case Phase::BeforeMarking: - return ¤tCycle().before; - case Phase::AfterMarking: - return ¤tCycle().after; - case Phase::BeforeGC: - case Phase::AfterGC: - // We should not be gathering live objects during these phases. - break; - } - RELEASE_ASSERT_NOT_REACHED(); - return nullptr; // Silencing a compiler warning. -} - -static void trimDeadObjectsFromList(HashSet<JSObject*>& knownLiveSet, LiveObjectList& list) -{ - if (!list.hasLiveObjects) - return; - - size_t liveObjectsFound = 0; - for (size_t i = 0; i < list.liveObjects.size(); i++) { - LiveObjectData& objData = list.liveObjects[i]; - if (objData.isConfirmedDead) - continue; // Don't "resurrect" known dead objects. - if (!knownLiveSet.contains(objData.obj)) { - objData.isConfirmedDead = true; - continue; - } - liveObjectsFound++; - } - list.hasLiveObjects = !!liveObjectsFound; -} - -void HeapVerifier::trimDeadObjects() -{ - HashSet<JSObject*> knownLiveSet; - - LiveObjectList& after = currentCycle().after; - for (size_t i = 0; i < after.liveObjects.size(); i++) { - LiveObjectData& objData = after.liveObjects[i]; - knownLiveSet.add(objData.obj); - } - - trimDeadObjectsFromList(knownLiveSet, currentCycle().before); - - for (int i = -1; i > -m_numberOfCycles; i--) { - trimDeadObjectsFromList(knownLiveSet, cycleForIndex(i).before); - trimDeadObjectsFromList(knownLiveSet, cycleForIndex(i).after); - } -} - -bool HeapVerifier::verifyButterflyIsInStorageSpace(Phase phase, LiveObjectList& list) -{ - auto& liveObjects = list.liveObjects; - - CopiedSpace& storageSpace = m_heap->m_storageSpace; - bool listNamePrinted = false; - bool success = true; - for (size_t i = 0; i < liveObjects.size(); i++) { - LiveObjectData& objectData = liveObjects[i]; - if (objectData.isConfirmedDead) - continue; - - JSObject* obj = objectData.obj; - Butterfly* butterfly = obj->butterfly(); - if (butterfly) { - void* butterflyBase; - size_t butterflyCapacityInBytes; - CopiedBlock* butterflyBlock; - getButterflyDetails(obj, butterflyBase, butterflyCapacityInBytes, butterflyBlock); - - if (!storageSpace.contains(butterflyBlock)) { - if (!listNamePrinted) { - dataLogF("Verification @ phase %s FAILED in object list '%s' (size %zu)\n", - phaseName(phase), list.name, liveObjects.size()); - listNamePrinted = true; - } - - Structure* structure = obj->structure(); - const char* structureClassName = structure->classInfo()->className; - dataLogF(" butterfly %p (base %p size %zu block %p) NOT in StorageSpace | obj %p type '%s'\n", - butterfly, butterflyBase, butterflyCapacityInBytes, butterflyBlock, obj, structureClassName); - success = false; - } - } - } - return success; -} - -void HeapVerifier::verify(HeapVerifier::Phase phase) -{ - bool beforeVerified = verifyButterflyIsInStorageSpace(phase, currentCycle().before); - bool afterVerified = verifyButterflyIsInStorageSpace(phase, currentCycle().after); - RELEASE_ASSERT(beforeVerified && afterVerified); -} - -void HeapVerifier::reportObject(LiveObjectData& objData, int cycleIndex, HeapVerifier::GCCycle& cycle, LiveObjectList& list) -{ - JSObject* obj = objData.obj; - - if (objData.isConfirmedDead) { - dataLogF("FOUND dead obj %p in GC[%d] %s list '%s'\n", - obj, cycleIndex, cycle.collectionTypeName(), list.name); - return; - } - - Structure* structure = obj->structure(); - Butterfly* butterfly = obj->butterfly(); - void* butterflyBase; - size_t butterflyCapacityInBytes; - CopiedBlock* butterflyBlock; - getButterflyDetails(obj, butterflyBase, butterflyCapacityInBytes, butterflyBlock); - - dataLogF("FOUND obj %p type '%s' butterfly %p (base %p size %zu block %p) in GC[%d] %s list '%s'\n", - obj, structure->classInfo()->className, - butterfly, butterflyBase, butterflyCapacityInBytes, butterflyBlock, - cycleIndex, cycle.collectionTypeName(), list.name); -} - -void HeapVerifier::checkIfRecorded(JSObject* obj) -{ - bool found = false; - - for (int cycleIndex = 0; cycleIndex > -m_numberOfCycles; cycleIndex--) { - GCCycle& cycle = cycleForIndex(cycleIndex); - LiveObjectList& beforeList = cycle.before; - LiveObjectList& afterList = cycle.after; - - LiveObjectData* objData; - objData = beforeList.findObject(obj); - if (objData) { - reportObject(*objData, cycleIndex, cycle, beforeList); - found = true; - } - objData = afterList.findObject(obj); - if (objData) { - reportObject(*objData, cycleIndex, cycle, afterList); - found = true; - } - } - - if (!found) - dataLogF("obj %p NOT FOUND\n", obj); -} - -} // namespace JSC |
