58e92d48a44b348e3681e1f42be1b883b984bc40
[WebKit-https.git] / Source / JavaScriptCore / heap / HeapInlines.h
1 /*
2  * Copyright (C) 2014 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 #ifndef HeapInlines_h
27 #define HeapInlines_h
28
29 #include "Heap.h"
30 #include "JSCell.h"
31 #include "Structure.h"
32
33 namespace JSC {
34
35 inline bool Heap::shouldCollect()
36 {
37     if (isDeferred())
38         return false;
39     if (Options::gcMaxHeapSize())
40         return m_bytesAllocatedThisCycle > Options::gcMaxHeapSize() && m_isSafeToCollect && m_operationInProgress == NoOperation;
41     return m_bytesAllocatedThisCycle > m_maxEdenSize && m_isSafeToCollect && m_operationInProgress == NoOperation;
42 }
43
44 inline bool Heap::isBusy()
45 {
46     return m_operationInProgress != NoOperation;
47 }
48
49 inline bool Heap::isCollecting()
50 {
51     return m_operationInProgress == FullCollection || m_operationInProgress == EdenCollection;
52 }
53
54 inline Heap* Heap::heap(const JSCell* cell)
55 {
56     return MarkedBlock::blockFor(cell)->heap();
57 }
58
59 inline Heap* Heap::heap(const JSValue v)
60 {
61     if (!v.isCell())
62         return 0;
63     return heap(v.asCell());
64 }
65
66 inline bool Heap::isLive(const void* cell)
67 {
68     return MarkedBlock::blockFor(cell)->isLiveCell(cell);
69 }
70
71 inline bool Heap::isRemembered(const void* ptr)
72 {
73     const JSCell* cell = static_cast<const JSCell*>(ptr);
74     ASSERT(cell);
75     ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread());
76     ASSERT(MarkedBlock::blockFor(cell)->isRemembered(cell) == cell->isRemembered());
77     return cell->isRemembered();
78 }
79
80 inline bool Heap::isMarked(const void* cell)
81 {
82     return MarkedBlock::blockFor(cell)->isMarked(cell);
83 }
84
85 inline bool Heap::testAndSetMarked(const void* cell)
86 {
87     return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
88 }
89
90 inline void Heap::setMarked(const void* cell)
91 {
92     MarkedBlock::blockFor(cell)->setMarked(cell);
93 }
94
95 inline bool Heap::isWriteBarrierEnabled()
96 {
97 #if ENABLE(WRITE_BARRIER_PROFILING) || ENABLE(GGC)
98     return true;
99 #else
100     return false;
101 #endif
102 }
103
104 inline void Heap::writeBarrier(const JSCell* from, JSValue to)
105 {
106 #if ENABLE(WRITE_BARRIER_PROFILING)
107     WriteBarrierCounters::countWriteBarrier();
108 #endif
109 #if ENABLE(GGC)
110     if (!to.isCell())
111         return;
112     writeBarrier(from, to.asCell());
113 #else
114     UNUSED_PARAM(from);
115     UNUSED_PARAM(to);
116 #endif
117 }
118
119 inline void Heap::writeBarrier(const JSCell* from, JSCell* to)
120 {
121 #if ENABLE(WRITE_BARRIER_PROFILING)
122     WriteBarrierCounters::countWriteBarrier();
123 #endif
124 #if ENABLE(GGC)
125     if (!from || !from->isMarked()) {
126         ASSERT(!from || !isMarked(from));
127         return;
128     }
129     if (!to || to->isMarked()) {
130         ASSERT(!to || isMarked(to));
131         return;
132     }
133     addToRememberedSet(from);
134 #else
135     UNUSED_PARAM(from);
136     UNUSED_PARAM(to);
137 #endif
138 }
139
140 inline void Heap::writeBarrier(const JSCell* from)
141 {
142 #if ENABLE(GGC)
143     ASSERT_GC_OBJECT_LOOKS_VALID(const_cast<JSCell*>(from));
144     if (!from || !from->isMarked()) {
145         ASSERT(!from || !isMarked(from));
146         return;
147     }
148     ASSERT(isMarked(from));
149     addToRememberedSet(from);
150 #else
151     UNUSED_PARAM(from);
152 #endif
153 }
154
155 inline void Heap::reportExtraMemoryCost(size_t cost)
156 {
157     if (cost > minExtraCost) 
158         reportExtraMemoryCostSlowCase(cost);
159 }
160
161 template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
162 {
163     for (auto& pair : m_protectedValues)
164         functor(pair.key);
165     m_handleSet.forEachStrongHandle(functor, m_protectedValues);
166
167     return functor.returnValue();
168 }
169
170 template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
171 {
172     Functor functor;
173     return forEachProtectedCell(functor);
174 }
175
176 template<typename Functor> inline void Heap::forEachCodeBlock(Functor& functor)
177 {
178     return m_codeBlocks.iterate<Functor>(functor);
179 }
180
181 inline void* Heap::allocateWithNormalDestructor(size_t bytes)
182 {
183 #if ENABLE(ALLOCATION_LOGGING)
184     dataLogF("JSC GC allocating %lu bytes with normal destructor.\n", bytes);
185 #endif
186     ASSERT(isValidAllocation(bytes));
187     return m_objectSpace.allocateWithNormalDestructor(bytes);
188 }
189
190 inline void* Heap::allocateWithImmortalStructureDestructor(size_t bytes)
191 {
192 #if ENABLE(ALLOCATION_LOGGING)
193     dataLogF("JSC GC allocating %lu bytes with immortal structure destructor.\n", bytes);
194 #endif
195     ASSERT(isValidAllocation(bytes));
196     return m_objectSpace.allocateWithImmortalStructureDestructor(bytes);
197 }
198
199 inline void* Heap::allocateWithoutDestructor(size_t bytes)
200 {
201 #if ENABLE(ALLOCATION_LOGGING)
202     dataLogF("JSC GC allocating %lu bytes without destructor.\n", bytes);
203 #endif
204     ASSERT(isValidAllocation(bytes));
205     return m_objectSpace.allocateWithoutDestructor(bytes);
206 }
207
208 template<typename ClassType>
209 void* Heap::allocateObjectOfType(size_t bytes)
210 {
211     if (ClassType::needsDestruction && ClassType::hasImmortalStructure)
212         return allocateWithImmortalStructureDestructor(bytes);
213     if (ClassType::needsDestruction)
214         return allocateWithNormalDestructor(bytes);
215     return allocateWithoutDestructor(bytes);
216 }
217
218 template<typename ClassType>
219 MarkedSpace::Subspace& Heap::subspaceForObjectOfType()
220 {
221     if (ClassType::needsDestruction && ClassType::hasImmortalStructure)
222         return subspaceForObjectsWithImmortalStructure();
223     if (ClassType::needsDestruction)
224         return subspaceForObjectNormalDestructor();
225     return subspaceForObjectWithoutDestructor();
226 }
227
228 template<typename ClassType>
229 MarkedAllocator& Heap::allocatorForObjectOfType(size_t bytes)
230 {
231     if (ClassType::needsDestruction && ClassType::hasImmortalStructure)
232         return allocatorForObjectWithImmortalStructureDestructor(bytes);
233     if (ClassType::needsDestruction)
234         return allocatorForObjectWithNormalDestructor(bytes);
235     return allocatorForObjectWithoutDestructor(bytes);
236 }
237
238 inline CheckedBoolean Heap::tryAllocateStorage(JSCell* intendedOwner, size_t bytes, void** outPtr)
239 {
240     CheckedBoolean result = m_storageSpace.tryAllocate(bytes, outPtr);
241 #if ENABLE(ALLOCATION_LOGGING)
242     dataLogF("JSC GC allocating %lu bytes of storage for %p: %p.\n", bytes, intendedOwner, *outPtr);
243 #else
244     UNUSED_PARAM(intendedOwner);
245 #endif
246     return result;
247 }
248
249 inline CheckedBoolean Heap::tryReallocateStorage(JSCell* intendedOwner, void** ptr, size_t oldSize, size_t newSize)
250 {
251 #if ENABLE(ALLOCATION_LOGGING)
252     void* oldPtr = *ptr;
253 #endif
254     CheckedBoolean result = m_storageSpace.tryReallocate(ptr, oldSize, newSize);
255 #if ENABLE(ALLOCATION_LOGGING)
256     dataLogF("JSC GC reallocating %lu -> %lu bytes of storage for %p: %p -> %p.\n", oldSize, newSize, intendedOwner, oldPtr, *ptr);
257 #else
258     UNUSED_PARAM(intendedOwner);
259 #endif
260     return result;
261 }
262
263 inline void Heap::ascribeOwner(JSCell* intendedOwner, void* storage)
264 {
265 #if ENABLE(ALLOCATION_LOGGING)
266     dataLogF("JSC GC ascribing %p as owner of storage %p.\n", intendedOwner, storage);
267 #else
268     UNUSED_PARAM(intendedOwner);
269     UNUSED_PARAM(storage);
270 #endif
271 }
272
273 #if USE(CF)
274 template <typename T>
275 inline void Heap::releaseSoon(RetainPtr<T>&& object)
276 {
277     m_delayedReleaseObjects.append(WTF::move(object));
278 }
279 #endif
280
281 inline void Heap::incrementDeferralDepth()
282 {
283     RELEASE_ASSERT(m_deferralDepth < 100); // Sanity check to make sure this doesn't get ridiculous.
284     m_deferralDepth++;
285 }
286
287 inline void Heap::decrementDeferralDepth()
288 {
289     RELEASE_ASSERT(m_deferralDepth >= 1);
290     m_deferralDepth--;
291 }
292
293 inline bool Heap::collectIfNecessaryOrDefer()
294 {
295     if (isDeferred())
296         return false;
297
298     if (!shouldCollect())
299         return false;
300
301     collect();
302     return true;
303 }
304
305 inline void Heap::decrementDeferralDepthAndGCIfNeeded()
306 {
307     decrementDeferralDepth();
308     collectIfNecessaryOrDefer();
309 }
310
311 inline HashSet<MarkedArgumentBuffer*>& Heap::markListSet()
312 {
313     if (!m_markListSet)
314         m_markListSet = std::make_unique<HashSet<MarkedArgumentBuffer*>>();
315     return *m_markListSet;
316 }
317
318 inline void Heap::registerWeakGCMap(void* weakGCMap, std::function<void()> pruningCallback)
319 {
320     m_weakGCMaps.add(weakGCMap, WTF::move(pruningCallback));
321 }
322
323 inline void Heap::unregisterWeakGCMap(void* weakGCMap)
324 {
325     m_weakGCMaps.remove(weakGCMap);
326 }
327     
328 } // namespace JSC
329
330 #endif // HeapInlines_h