CodeBlocks should be in IsoSubspaces
[WebKit-https.git] / Source / JavaScriptCore / heap / SlotVisitor.h
1 /*
2  * Copyright (C) 2011-2017 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include "HandleTypes.h"
29 #include "IterationStatus.h"
30 #include "MarkStack.h"
31 #include "VisitRaceKey.h"
32 #include <wtf/MonotonicTime.h>
33 #include <wtf/text/CString.h>
34
35 namespace JSC {
36
37 class ConservativeRoots;
38 class GCThreadSharedData;
39 class Heap;
40 class HeapCell;
41 class HeapSnapshotBuilder;
42 class MarkedBlock;
43 class MarkingConstraintSolver;
44 class UnconditionalFinalizer;
45 template<typename T> class Weak;
46 class WeakReferenceHarvester;
47 template<typename T> class WriteBarrierBase;
48
49 typedef uint32_t HeapVersion;
50
51 class SlotVisitor {
52     WTF_MAKE_NONCOPYABLE(SlotVisitor);
53     WTF_MAKE_FAST_ALLOCATED;
54
55     friend class SetCurrentCellScope;
56     friend class Heap;
57
58 public:
59     SlotVisitor(Heap&, CString codeName);
60     ~SlotVisitor();
61
62     MarkStackArray& collectorMarkStack() { return m_collectorStack; }
63     MarkStackArray& mutatorMarkStack() { return m_mutatorStack; }
64     const MarkStackArray& collectorMarkStack() const { return m_collectorStack; }
65     const MarkStackArray& mutatorMarkStack() const { return m_mutatorStack; }
66     
67     VM& vm();
68     const VM& vm() const;
69     Heap* heap() const;
70
71     void append(ConservativeRoots&);
72     
73     template<typename T> void append(const WriteBarrierBase<T>&);
74     template<typename T> void appendHidden(const WriteBarrierBase<T>&);
75     template<typename Iterator> void append(Iterator begin , Iterator end);
76     void appendValues(const WriteBarrierBase<Unknown>*, size_t count);
77     void appendValuesHidden(const WriteBarrierBase<Unknown>*, size_t count);
78     
79     // These don't require you to prove that you have a WriteBarrier<>. That makes sense
80     // for:
81     //
82     // - roots.
83     // - sophisticated data structures that barrier through other means (like DFG::Plan and
84     //   friends).
85     //
86     // If you are not a root and you don't know what kind of barrier you have, then you
87     // shouldn't call these methods.
88     void appendUnbarriered(JSValue);
89     void appendUnbarriered(JSValue*, size_t);
90     void appendUnbarriered(JSCell*);
91     
92     template<typename T>
93     void append(const Weak<T>& weak);
94     
95     void appendHiddenUnbarriered(JSValue);
96     void appendHiddenUnbarriered(JSCell*);
97
98     bool addOpaqueRoot(void*); // Returns true if the root was new.
99     
100     bool containsOpaqueRoot(void*) const;
101
102     bool isEmpty() { return m_collectorStack.isEmpty() && m_mutatorStack.isEmpty(); }
103
104     void didStartMarking();
105     void reset();
106     void clearMarkStacks();
107
108     size_t bytesVisited() const { return m_bytesVisited; }
109     size_t visitCount() const { return m_visitCount; }
110     
111     void addToVisitCount(size_t value) { m_visitCount += value; }
112
113     void donate();
114     void drain(MonotonicTime timeout = MonotonicTime::infinity());
115     void donateAndDrain(MonotonicTime timeout = MonotonicTime::infinity());
116     
117     enum SharedDrainMode { SlaveDrain, MasterDrain };
118     enum class SharedDrainResult { Done, TimedOut };
119     SharedDrainResult drainFromShared(SharedDrainMode, MonotonicTime timeout = MonotonicTime::infinity());
120
121     SharedDrainResult drainInParallel(MonotonicTime timeout = MonotonicTime::infinity());
122     SharedDrainResult drainInParallelPassively(MonotonicTime timeout = MonotonicTime::infinity());
123     
124     SharedDrainResult waitForTermination(MonotonicTime timeout = MonotonicTime::infinity());
125
126     // Attempts to perform an increment of draining that involves only walking `bytes` worth of data. This
127     // is likely to accidentally walk more or less than that. It will usually mark more than bytes. It may
128     // mark less than bytes if we're reaching termination or if the global worklist is empty (which may in
129     // rare cases happen temporarily even if we're not reaching termination).
130     size_t performIncrementOfDraining(size_t bytes);
131     
132     // This informs the GC about auxiliary of some size that we are keeping alive. If you don't do
133     // this then the space will be freed at end of GC.
134     void markAuxiliary(const void* base);
135
136     void reportExtraMemoryVisited(size_t);
137 #if ENABLE(RESOURCE_USAGE)
138     void reportExternalMemoryVisited(size_t);
139 #endif
140     
141     void addWeakReferenceHarvester(WeakReferenceHarvester*);
142     void addUnconditionalFinalizer(UnconditionalFinalizer*);
143
144     void dump(PrintStream&) const;
145
146     bool isBuildingHeapSnapshot() const { return !!m_heapSnapshotBuilder; }
147     
148     HeapVersion markingVersion() const { return m_markingVersion; }
149
150     bool mutatorIsStopped() const { return m_mutatorIsStopped; }
151     
152     Lock& rightToRun() { return m_rightToRun; }
153     
154     void updateMutatorIsStopped(const AbstractLocker&);
155     void updateMutatorIsStopped();
156     
157     bool hasAcknowledgedThatTheMutatorIsResumed() const;
158     bool mutatorIsStoppedIsUpToDate() const;
159     
160     void optimizeForStoppedMutator();
161     
162     void didRace(const VisitRaceKey&);
163     void didRace(JSCell* cell, const char* reason) { didRace(VisitRaceKey(cell, reason)); }
164     
165     void visitAsConstraint(const JSCell*);
166     
167     bool didReachTermination();
168     
169     void setIgnoreNewOpaqueRoots(bool value) { m_ignoreNewOpaqueRoots = value; }
170
171     void donateAll();
172     
173     const char* codeName() const { return m_codeName.data(); }
174     
175     JS_EXPORT_PRIVATE void addParallelConstraintTask(RefPtr<SharedTask<void(SlotVisitor&)>>);
176
177 private:
178     friend class ParallelModeEnabler;
179     friend class MarkingConstraintSolver;
180     
181     void appendJSCellOrAuxiliary(HeapCell*);
182
183     JS_EXPORT_PRIVATE void appendSlow(JSCell*, Dependency);
184     JS_EXPORT_PRIVATE void appendHiddenSlow(JSCell*, Dependency);
185     void appendHiddenSlowImpl(JSCell*, Dependency);
186     
187     template<typename ContainerType>
188     void setMarkedAndAppendToMarkStack(ContainerType&, JSCell*, Dependency);
189     
190     void appendToMarkStack(JSCell*);
191     
192     template<typename ContainerType>
193     void appendToMarkStack(ContainerType&, JSCell*);
194     
195     void appendToMutatorMarkStack(const JSCell*);
196     
197     void noteLiveAuxiliaryCell(HeapCell*);
198     
199     void visitChildren(const JSCell*);
200     
201     void donateKnownParallel();
202     void donateKnownParallel(MarkStackArray& from, MarkStackArray& to);
203
204     void donateAll(const AbstractLocker&);
205
206     bool hasWork(const AbstractLocker&);
207     bool didReachTermination(const AbstractLocker&);
208
209     template<typename Func>
210     IterationStatus forEachMarkStack(const Func&);
211
212     MarkStackArray& correspondingGlobalStack(MarkStackArray&);
213
214     MarkStackArray m_collectorStack;
215     MarkStackArray m_mutatorStack;
216     bool m_ignoreNewOpaqueRoots { false }; // Useful as a debugging mode.
217     
218     size_t m_bytesVisited;
219     size_t m_visitCount;
220     size_t m_nonCellVisitCount { 0 }; // Used for incremental draining, ignored otherwise.
221     bool m_isInParallelMode;
222
223     HeapVersion m_markingVersion;
224     
225     Heap& m_heap;
226
227     HeapSnapshotBuilder* m_heapSnapshotBuilder { nullptr };
228     JSCell* m_currentCell { nullptr };
229     bool m_isFirstVisit { false };
230     bool m_mutatorIsStopped { false };
231     bool m_canOptimizeForStoppedMutator { false };
232     Lock m_rightToRun;
233     
234     CString m_codeName;
235     
236     MarkingConstraint* m_currentConstraint { nullptr };
237     MarkingConstraintSolver* m_currentSolver { nullptr };
238     
239 public:
240 #if !ASSERT_DISABLED
241     bool m_isCheckingForDefaultMarkViolation;
242     bool m_isDraining;
243 #endif
244 };
245
246 class ParallelModeEnabler {
247 public:
248     ParallelModeEnabler(SlotVisitor& stack)
249         : m_stack(stack)
250     {
251         ASSERT(!m_stack.m_isInParallelMode);
252         m_stack.m_isInParallelMode = true;
253     }
254     
255     ~ParallelModeEnabler()
256     {
257         ASSERT(m_stack.m_isInParallelMode);
258         m_stack.m_isInParallelMode = false;
259     }
260     
261 private:
262     SlotVisitor& m_stack;
263 };
264
265 } // namespace JSC