Unreviewed, rolling out r209766.
[WebKit.git] / Source / JavaScriptCore / heap / 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 GatherLiveObjFunctor : MarkedBlock::CountFunctor {
70     GatherLiveObjFunctor(LiveObjectList& list)
71         : m_list(list)
72     {
73         ASSERT(!list.liveObjects.size());
74     }
75
76     inline void visit(JSCell* cell)
77     {
78         if (!cell->isObject())
79             return;        
80         LiveObjectData data(asObject(cell));
81         m_list.liveObjects.append(data);
82     }
83
84     IterationStatus operator()(HeapCell* cell, HeapCell::Kind kind) const
85     {
86         if (kind == HeapCell::JSCell) {
87             // FIXME: This const_cast exists because this isn't a C++ lambda.
88             // https://bugs.webkit.org/show_bug.cgi?id=159644
89             const_cast<GatherLiveObjFunctor*>(this)->visit(static_cast<JSCell*>(cell));
90         }
91         return IterationStatus::Continue;
92     }
93
94     LiveObjectList& m_list;
95 };
96
97 void HeapVerifier::gatherLiveObjects(HeapVerifier::Phase phase)
98 {
99     Heap* heap = m_heap;
100     LiveObjectList& list = *liveObjectListForGathering(phase);
101
102     HeapIterationScope iterationScope(*heap);
103     list.reset();
104     GatherLiveObjFunctor functor(list);
105     heap->m_objectSpace.forEachLiveCell(iterationScope, functor);
106 }
107
108 LiveObjectList* HeapVerifier::liveObjectListForGathering(HeapVerifier::Phase phase)
109 {
110     switch (phase) {
111     case Phase::BeforeMarking:
112         return &currentCycle().before;
113     case Phase::AfterMarking:
114         return &currentCycle().after;
115     case Phase::BeforeGC:
116     case Phase::AfterGC:
117         // We should not be gathering live objects during these phases.
118         break;
119     }
120     RELEASE_ASSERT_NOT_REACHED();
121     return nullptr; // Silencing a compiler warning.
122 }
123
124 static void trimDeadObjectsFromList(HashSet<JSObject*>& knownLiveSet, LiveObjectList& list)
125 {
126     if (!list.hasLiveObjects)
127         return;
128
129     size_t liveObjectsFound = 0;
130     for (size_t i = 0; i < list.liveObjects.size(); i++) {
131         LiveObjectData& objData = list.liveObjects[i];
132         if (objData.isConfirmedDead)
133             continue; // Don't "resurrect" known dead objects.
134         if (!knownLiveSet.contains(objData.obj)) {
135             objData.isConfirmedDead = true;
136             continue;
137         }
138         liveObjectsFound++;
139     }
140     list.hasLiveObjects = !!liveObjectsFound;
141 }
142
143 void HeapVerifier::trimDeadObjects()
144 {
145     HashSet<JSObject*> knownLiveSet;
146
147     LiveObjectList& after = currentCycle().after;
148     for (size_t i = 0; i < after.liveObjects.size(); i++) {
149         LiveObjectData& objData = after.liveObjects[i];
150         knownLiveSet.add(objData.obj);
151     }
152
153     trimDeadObjectsFromList(knownLiveSet, currentCycle().before);
154
155     for (int i = -1; i > -m_numberOfCycles; i--) {
156         trimDeadObjectsFromList(knownLiveSet, cycleForIndex(i).before);
157         trimDeadObjectsFromList(knownLiveSet, cycleForIndex(i).after);
158     }
159 }
160
161 bool HeapVerifier::verifyButterflyIsInStorageSpace(Phase, LiveObjectList&)
162 {
163     // FIXME: Make this work again. https://bugs.webkit.org/show_bug.cgi?id=161752
164     return true;
165 }
166
167 void HeapVerifier::verify(HeapVerifier::Phase phase)
168 {
169     bool beforeVerified = verifyButterflyIsInStorageSpace(phase, currentCycle().before);
170     bool afterVerified = verifyButterflyIsInStorageSpace(phase, currentCycle().after);
171     RELEASE_ASSERT(beforeVerified && afterVerified);
172 }
173
174 void HeapVerifier::reportObject(LiveObjectData& objData, int cycleIndex, HeapVerifier::GCCycle& cycle, LiveObjectList& list)
175 {
176     JSObject* obj = objData.obj;
177
178     if (objData.isConfirmedDead) {
179         dataLogF("FOUND dead obj %p in GC[%d] %s list '%s'\n",
180             obj, cycleIndex, collectionScopeName(cycle.scope), list.name);
181         return;
182     }
183
184     Structure* structure = obj->structure();
185     Butterfly* butterfly = obj->butterfly();
186     void* butterflyBase = butterfly->base(structure);
187
188     dataLogF("FOUND obj %p type '%s' butterfly %p (base %p) in GC[%d] %s list '%s'\n",
189         obj, structure->classInfo()->className,
190         butterfly, butterflyBase,
191         cycleIndex, collectionScopeName(cycle.scope), list.name);
192 }
193
194 void HeapVerifier::checkIfRecorded(JSObject* obj)
195 {
196     bool found = false;
197
198     for (int cycleIndex = 0; cycleIndex > -m_numberOfCycles; cycleIndex--) {
199         GCCycle& cycle = cycleForIndex(cycleIndex);
200         LiveObjectList& beforeList = cycle.before; 
201         LiveObjectList& afterList = cycle.after; 
202
203         LiveObjectData* objData;
204         objData = beforeList.findObject(obj);
205         if (objData) {
206             reportObject(*objData, cycleIndex, cycle, beforeList);
207             found = true;
208         }
209         objData = afterList.findObject(obj);
210         if (objData) {
211             reportObject(*objData, cycleIndex, cycle, afterList);
212             found = true;
213         }
214     }
215
216     if (!found)
217         dataLogF("obj %p NOT FOUND\n", obj);
218 }
219
220 } // namespace JSC