3959e95a1012c46ecd9fcc4b7beb114025949dc6
[WebKit-https.git] / Source / JavaScriptCore / tools / HeapVerifier.cpp
1 /*
2  * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "HeapVerifier.h"
28
29 #include "ButterflyInlines.h"
30 #include "HeapIterationScope.h"
31 #include "JSCInlines.h"
32 #include "JSObject.h"
33 #include "MarkedSpaceInlines.h"
34
35 namespace JSC {
36
37 HeapVerifier::HeapVerifier(Heap* heap, unsigned numberOfGCCyclesToRecord)
38     : m_heap(heap)
39     , m_currentCycle(0)
40     , m_numberOfCycles(numberOfGCCyclesToRecord)
41 {
42     RELEASE_ASSERT(m_numberOfCycles > 0);
43     m_cycles = std::make_unique<GCCycle[]>(m_numberOfCycles);
44 }
45
46 const char* HeapVerifier::phaseName(HeapVerifier::Phase phase)
47 {
48     switch (phase) {
49     case Phase::BeforeGC:
50         return "BeforeGC";
51     case Phase::BeforeMarking:
52         return "BeforeMarking";
53     case Phase::AfterMarking:
54         return "AfterMarking";
55     case Phase::AfterGC:
56         return "AfterGC";
57     }
58     RELEASE_ASSERT_NOT_REACHED();
59     return nullptr; // Silencing a compiler warning.
60 }
61
62 void HeapVerifier::initializeGCCycle()
63 {
64     Heap* heap = m_heap;
65     incrementCycle();
66     currentCycle().scope = *heap->collectionScope();
67 }
68
69 struct GatherCellFunctor : MarkedBlock::CountFunctor {
70     GatherCellFunctor(CellList& list)
71         : m_list(list)
72     {
73         ASSERT(!list.liveCells.size());
74     }
75
76     inline void visit(JSCell* cell)
77     {
78         CellProfile profile(cell);
79         m_list.liveCells.append(profile);
80     }
81
82     IterationStatus operator()(HeapCell* cell, HeapCell::Kind kind) const
83     {
84         if (kind == HeapCell::JSCell) {
85             // FIXME: This const_cast exists because this isn't a C++ lambda.
86             // https://bugs.webkit.org/show_bug.cgi?id=159644
87             const_cast<GatherCellFunctor*>(this)->visit(static_cast<JSCell*>(cell));
88         }
89         return IterationStatus::Continue;
90     }
91
92     CellList& m_list;
93 };
94
95 void HeapVerifier::gatherLiveCells(HeapVerifier::Phase phase)
96 {
97     Heap* heap = m_heap;
98     CellList& list = *cellListForGathering(phase);
99
100     HeapIterationScope iterationScope(*heap);
101     list.reset();
102     GatherCellFunctor functor(list);
103     heap->m_objectSpace.forEachLiveCell(iterationScope, functor);
104 }
105
106 CellList* HeapVerifier::cellListForGathering(HeapVerifier::Phase phase)
107 {
108     switch (phase) {
109     case Phase::BeforeMarking:
110         return &currentCycle().before;
111     case Phase::AfterMarking:
112         return &currentCycle().after;
113     case Phase::BeforeGC:
114     case Phase::AfterGC:
115         // We should not be gathering live cells during these phases.
116         break;
117     }
118     RELEASE_ASSERT_NOT_REACHED();
119     return nullptr; // Silencing a compiler warning.
120 }
121
122 static void trimDeadCellsFromList(HashSet<JSCell*>& knownLiveSet, CellList& list)
123 {
124     if (!list.hasLiveCells)
125         return;
126
127     size_t liveCellsFound = 0;
128     for (auto& cellProfile : list.liveCells) {
129         if (cellProfile.isConfirmedDead)
130             continue; // Don't "resurrect" known dead cells.
131         if (!knownLiveSet.contains(cellProfile.cell)) {
132             cellProfile.isConfirmedDead = true;
133             continue;
134         }
135         liveCellsFound++;
136     }
137     list.hasLiveCells = !!liveCellsFound;
138 }
139
140 void HeapVerifier::trimDeadCells()
141 {
142     HashSet<JSCell*> knownLiveSet;
143
144     CellList& after = currentCycle().after;
145     for (auto& cellProfile : after.liveCells)
146         knownLiveSet.add(cellProfile.cell);
147
148     trimDeadCellsFromList(knownLiveSet, currentCycle().before);
149
150     for (int i = -1; i > -m_numberOfCycles; i--) {
151         trimDeadCellsFromList(knownLiveSet, cycleForIndex(i).before);
152         trimDeadCellsFromList(knownLiveSet, cycleForIndex(i).after);
153     }
154 }
155
156 bool HeapVerifier::verifyButterflyIsInStorageSpace(Phase, CellList&)
157 {
158     // FIXME: Make this work again. https://bugs.webkit.org/show_bug.cgi?id=161752
159     return true;
160 }
161
162 void HeapVerifier::verify(HeapVerifier::Phase phase)
163 {
164     bool beforeVerified = verifyButterflyIsInStorageSpace(phase, currentCycle().before);
165     bool afterVerified = verifyButterflyIsInStorageSpace(phase, currentCycle().after);
166     RELEASE_ASSERT(beforeVerified && afterVerified);
167 }
168
169 void HeapVerifier::reportCell(CellProfile& cellProfile, int cycleIndex, HeapVerifier::GCCycle& cycle, CellList& list)
170 {
171     JSCell* cell = cellProfile.cell;
172
173     if (cellProfile.isConfirmedDead) {
174         dataLogF("FOUND dead cell %p in GC[%d] %s list '%s'\n",
175             cell, cycleIndex, collectionScopeName(cycle.scope), list.name);
176         return;
177     }
178
179     if (cell->isObject()) {
180         JSObject* object = static_cast<JSObject*>(cell);
181         Structure* structure = object->structure();
182         Butterfly* butterfly = object->butterfly();
183         void* butterflyBase = butterfly->base(structure);
184
185         dataLogF("FOUND object %p type '%s' butterfly %p (base %p) in GC[%d] %s list '%s'\n",
186             object, structure->classInfo()->className,
187             butterfly, butterflyBase,
188             cycleIndex, collectionScopeName(cycle.scope), list.name);
189     } else {
190         Structure* structure = cell->structure();
191         dataLogF("FOUND cell %p type '%s' in GC[%d] %s list '%s'\n",
192             cell, structure->classInfo()->className,
193             cycleIndex, collectionScopeName(cycle.scope), list.name);
194     }
195 }
196
197 void HeapVerifier::checkIfRecorded(JSCell* cell)
198 {
199     bool found = false;
200
201     for (int cycleIndex = 0; cycleIndex > -m_numberOfCycles; cycleIndex--) {
202         GCCycle& cycle = cycleForIndex(cycleIndex);
203         CellList& beforeList = cycle.before;
204         CellList& afterList = cycle.after;
205
206         CellProfile* profile;
207         profile = beforeList.findCell(cell);
208         if (profile) {
209             reportCell(*profile, cycleIndex, cycle, beforeList);
210             found = true;
211         }
212         profile = afterList.findCell(cell);
213         if (profile) {
214             reportCell(*profile, cycleIndex, cycle, afterList);
215             found = true;
216         }
217     }
218
219     if (!found)
220         dataLogF("cell %p NOT FOUND\n", cell);
221 }
222
223 } // namespace JSC