GC constraint solving should be parallel
[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 UnconditionalFinalizer;
44 template<typename T> class Weak;
45 class WeakReferenceHarvester;
46 template<typename T> class WriteBarrierBase;
47
48 typedef uint32_t HeapVersion;
49
50 class SlotVisitor {
51     WTF_MAKE_NONCOPYABLE(SlotVisitor);
52     WTF_MAKE_FAST_ALLOCATED;
53
54     friend class SetCurrentCellScope;
55     friend class Heap;
56
57 public:
58     SlotVisitor(Heap&, CString codeName);
59     ~SlotVisitor();
60
61     MarkStackArray& collectorMarkStack() { return m_collectorStack; }
62     MarkStackArray& mutatorMarkStack() { return m_mutatorStack; }
63     const MarkStackArray& collectorMarkStack() const { return m_collectorStack; }
64     const MarkStackArray& mutatorMarkStack() const { return m_mutatorStack; }
65     
66     VM& vm();
67     const VM& vm() const;
68     Heap* heap() const;
69
70     void append(ConservativeRoots&);
71     
72     template<typename T> void append(const WriteBarrierBase<T>&);
73     template<typename T> void appendHidden(const WriteBarrierBase<T>&);
74     template<typename Iterator> void append(Iterator begin , Iterator end);
75     void appendValues(const WriteBarrierBase<Unknown>*, size_t count);
76     void appendValuesHidden(const WriteBarrierBase<Unknown>*, size_t count);
77     
78     // These don't require you to prove that you have a WriteBarrier<>. That makes sense
79     // for:
80     //
81     // - roots.
82     // - sophisticated data structures that barrier through other means (like DFG::Plan and
83     //   friends).
84     //
85     // If you are not a root and you don't know what kind of barrier you have, then you
86     // shouldn't call these methods.
87     void appendUnbarriered(JSValue);
88     void appendUnbarriered(JSValue*, size_t);
89     void appendUnbarriered(JSCell*);
90     
91     template<typename T>
92     void append(const Weak<T>& weak);
93     
94     void appendHiddenUnbarriered(JSValue);
95     void appendHiddenUnbarriered(JSCell*);
96
97     bool addOpaqueRoot(void*); // Returns true if the root was new.
98     
99     bool containsOpaqueRoot(void*) const;
100
101     bool isEmpty() { return m_collectorStack.isEmpty() && m_mutatorStack.isEmpty(); }
102
103     void didStartMarking();
104     void reset();
105     void clearMarkStacks();
106
107     size_t bytesVisited() const { return m_bytesVisited; }
108     size_t visitCount() const { return m_visitCount; }
109     
110     void addToVisitCount(size_t value) { m_visitCount += value; }
111
112     void donate();
113     void drain(MonotonicTime timeout = MonotonicTime::infinity());
114     void donateAndDrain(MonotonicTime timeout = MonotonicTime::infinity());
115     
116     enum SharedDrainMode { SlaveDrain, MasterDrain };
117     enum class SharedDrainResult { Done, TimedOut };
118     SharedDrainResult drainFromShared(SharedDrainMode, MonotonicTime timeout = MonotonicTime::infinity());
119
120     SharedDrainResult drainInParallel(MonotonicTime timeout = MonotonicTime::infinity());
121     SharedDrainResult drainInParallelPassively(MonotonicTime timeout = MonotonicTime::infinity());
122     
123     SharedDrainResult waitForTermination(MonotonicTime timeout = MonotonicTime::infinity());
124
125     // Attempts to perform an increment of draining that involves only walking `bytes` worth of data. This
126     // is likely to accidentally walk more or less than that. It will usually mark more than bytes. It may
127     // mark less than bytes if we're reaching termination or if the global worklist is empty (which may in
128     // rare cases happen temporarily even if we're not reaching termination).
129     size_t performIncrementOfDraining(size_t bytes);
130     
131     // This informs the GC about auxiliary of some size that we are keeping alive. If you don't do
132     // this then the space will be freed at end of GC.
133     void markAuxiliary(const void* base);
134
135     void reportExtraMemoryVisited(size_t);
136 #if ENABLE(RESOURCE_USAGE)
137     void reportExternalMemoryVisited(size_t);
138 #endif
139     
140     void addWeakReferenceHarvester(WeakReferenceHarvester*);
141     void addUnconditionalFinalizer(UnconditionalFinalizer*);
142
143     void dump(PrintStream&) const;
144
145     bool isBuildingHeapSnapshot() const { return !!m_heapSnapshotBuilder; }
146     
147     HeapVersion markingVersion() const { return m_markingVersion; }
148
149     bool mutatorIsStopped() const { return m_mutatorIsStopped; }
150     
151     Lock& rightToRun() { return m_rightToRun; }
152     
153     void updateMutatorIsStopped(const AbstractLocker&);
154     void updateMutatorIsStopped();
155     
156     bool hasAcknowledgedThatTheMutatorIsResumed() const;
157     bool mutatorIsStoppedIsUpToDate() const;
158     
159     void optimizeForStoppedMutator();
160     
161     void didRace(const VisitRaceKey&);
162     void didRace(JSCell* cell, const char* reason) { didRace(VisitRaceKey(cell, reason)); }
163     
164     void visitAsConstraint(const JSCell*);
165     
166     bool didReachTermination();
167     
168     void setIgnoreNewOpaqueRoots(bool value) { m_ignoreNewOpaqueRoots = value; }
169
170     void donateAll();
171     
172     const char* codeName() const { return m_codeName.data(); }
173
174 private:
175     friend class ParallelModeEnabler;
176     
177     void appendJSCellOrAuxiliary(HeapCell*);
178
179     JS_EXPORT_PRIVATE void appendSlow(JSCell*, Dependency);
180     JS_EXPORT_PRIVATE void appendHiddenSlow(JSCell*, Dependency);
181     void appendHiddenSlowImpl(JSCell*, Dependency);
182     
183     template<typename ContainerType>
184     void setMarkedAndAppendToMarkStack(ContainerType&, JSCell*, Dependency);
185     
186     void appendToMarkStack(JSCell*);
187     
188     template<typename ContainerType>
189     void appendToMarkStack(ContainerType&, JSCell*);
190     
191     void appendToMutatorMarkStack(const JSCell*);
192     
193     void noteLiveAuxiliaryCell(HeapCell*);
194     
195     void visitChildren(const JSCell*);
196     
197     void donateKnownParallel();
198     void donateKnownParallel(MarkStackArray& from, MarkStackArray& to);
199
200     void donateAll(const AbstractLocker&);
201
202     bool hasWork(const AbstractLocker&);
203     bool didReachTermination(const AbstractLocker&);
204
205     template<typename Func>
206     IterationStatus forEachMarkStack(const Func&);
207
208     MarkStackArray& correspondingGlobalStack(MarkStackArray&);
209
210     MarkStackArray m_collectorStack;
211     MarkStackArray m_mutatorStack;
212     bool m_ignoreNewOpaqueRoots { false }; // Useful as a debugging mode.
213     
214     size_t m_bytesVisited;
215     size_t m_visitCount;
216     size_t m_nonCellVisitCount { 0 }; // Used for incremental draining, ignored otherwise.
217     bool m_isInParallelMode;
218
219     HeapVersion m_markingVersion;
220     
221     Heap& m_heap;
222
223     HeapSnapshotBuilder* m_heapSnapshotBuilder { nullptr };
224     JSCell* m_currentCell { nullptr };
225     bool m_isFirstVisit { false };
226     bool m_mutatorIsStopped { false };
227     bool m_canOptimizeForStoppedMutator { false };
228     Lock m_rightToRun;
229     
230     CString m_codeName;
231     
232 public:
233 #if !ASSERT_DISABLED
234     bool m_isCheckingForDefaultMarkViolation;
235     bool m_isDraining;
236 #endif
237 };
238
239 class ParallelModeEnabler {
240 public:
241     ParallelModeEnabler(SlotVisitor& stack)
242         : m_stack(stack)
243     {
244         ASSERT(!m_stack.m_isInParallelMode);
245         m_stack.m_isInParallelMode = true;
246     }
247     
248     ~ParallelModeEnabler()
249     {
250         ASSERT(m_stack.m_isInParallelMode);
251         m_stack.m_isInParallelMode = false;
252     }
253     
254 private:
255     SlotVisitor& m_stack;
256 };
257
258 } // namespace JSC