Objective-C API external object graphs don't handle generational collection properly
[WebKit-https.git] / Source / JavaScriptCore / heap / Heap.cpp
1 /*
2  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2013, 2014 Apple Inc. All rights reserved.
3  *  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 #include "config.h"
22 #include "Heap.h"
23
24 #include "CodeBlock.h"
25 #include "ConservativeRoots.h"
26 #include "CopiedSpace.h"
27 #include "CopiedSpaceInlines.h"
28 #include "CopyVisitorInlines.h"
29 #include "DFGWorklist.h"
30 #include "DelayedReleaseScope.h"
31 #include "EdenGCActivityCallback.h"
32 #include "FullGCActivityCallback.h"
33 #include "GCActivityCallback.h"
34 #include "GCIncomingRefCountedSetInlines.h"
35 #include "HeapIterationScope.h"
36 #include "HeapRootVisitor.h"
37 #include "HeapStatistics.h"
38 #include "IncrementalSweeper.h"
39 #include "Interpreter.h"
40 #include "JSGlobalObject.h"
41 #include "JSLock.h"
42 #include "JSONObject.h"
43 #include "JSCInlines.h"
44 #include "JSVirtualMachineInternal.h"
45 #include "RecursiveAllocationScope.h"
46 #include "Tracing.h"
47 #include "UnlinkedCodeBlock.h"
48 #include "VM.h"
49 #include "WeakSetInlines.h"
50 #include <algorithm>
51 #include <wtf/RAMSize.h>
52 #include <wtf/CurrentTime.h>
53 #include <wtf/ProcessID.h>
54
55 using namespace std;
56 using namespace JSC;
57
58 namespace JSC {
59
60 namespace { 
61
62 static const size_t largeHeapSize = 32 * MB; // About 1.5X the average webpage.
63 static const size_t smallHeapSize = 1 * MB; // Matches the FastMalloc per-thread cache.
64
65 #define ENABLE_GC_LOGGING 0
66
67 #if ENABLE(GC_LOGGING)
68 #if COMPILER(CLANG)
69 #define DEFINE_GC_LOGGING_GLOBAL(type, name, arguments) \
70 _Pragma("clang diagnostic push") \
71 _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \
72 _Pragma("clang diagnostic ignored \"-Wexit-time-destructors\"") \
73 static type name arguments; \
74 _Pragma("clang diagnostic pop")
75 #else
76 #define DEFINE_GC_LOGGING_GLOBAL(type, name, arguments) \
77 static type name arguments;
78 #endif // COMPILER(CLANG)
79
80 struct GCTimer {
81     GCTimer(const char* name)
82         : m_name(name)
83     {
84     }
85     ~GCTimer()
86     {
87         logData(m_allCollectionData, "(All)");
88         logData(m_edenCollectionData, "(Eden)");
89         logData(m_fullCollectionData, "(Full)");
90     }
91
92     struct TimeRecord {
93         TimeRecord()
94             : m_time(0)
95             , m_min(std::numeric_limits<double>::infinity())
96             , m_max(0)
97             , m_count(0)
98         {
99         }
100
101         double m_time;
102         double m_min;
103         double m_max;
104         size_t m_count;
105     };
106
107     void logData(const TimeRecord& data, const char* extra)
108     {
109         dataLogF("[%d] %s %s: %.2lfms (avg. %.2lf, min. %.2lf, max. %.2lf, count %lu)\n", 
110             getCurrentProcessID(),
111             m_name, extra, 
112             data.m_time * 1000, 
113             data.m_time * 1000 / data.m_count, 
114             data.m_min * 1000, 
115             data.m_max * 1000,
116             data.m_count);
117     }
118
119     void updateData(TimeRecord& data, double duration)
120     {
121         if (duration < data.m_min)
122             data.m_min = duration;
123         if (duration > data.m_max)
124             data.m_max = duration;
125         data.m_count++;
126         data.m_time += duration;
127     }
128
129     void didFinishPhase(HeapOperation collectionType, double duration)
130     {
131         TimeRecord& data = collectionType == EdenCollection ? m_edenCollectionData : m_fullCollectionData;
132         updateData(data, duration);
133         updateData(m_allCollectionData, duration);
134     }
135
136     TimeRecord m_allCollectionData;
137     TimeRecord m_fullCollectionData;
138     TimeRecord m_edenCollectionData;
139     const char* m_name;
140 };
141
142 struct GCTimerScope {
143     GCTimerScope(GCTimer* timer, HeapOperation collectionType)
144         : m_timer(timer)
145         , m_start(WTF::monotonicallyIncreasingTime())
146         , m_collectionType(collectionType)
147     {
148     }
149     ~GCTimerScope()
150     {
151         double delta = WTF::monotonicallyIncreasingTime() - m_start;
152         m_timer->didFinishPhase(m_collectionType, delta);
153     }
154     GCTimer* m_timer;
155     double m_start;
156     HeapOperation m_collectionType;
157 };
158
159 struct GCCounter {
160     GCCounter(const char* name)
161         : m_name(name)
162         , m_count(0)
163         , m_total(0)
164         , m_min(10000000)
165         , m_max(0)
166     {
167     }
168     
169     void count(size_t amount)
170     {
171         m_count++;
172         m_total += amount;
173         if (amount < m_min)
174             m_min = amount;
175         if (amount > m_max)
176             m_max = amount;
177     }
178     ~GCCounter()
179     {
180         dataLogF("[%d] %s: %zu values (avg. %zu, min. %zu, max. %zu)\n", getCurrentProcessID(), m_name, m_total, m_total / m_count, m_min, m_max);
181     }
182     const char* m_name;
183     size_t m_count;
184     size_t m_total;
185     size_t m_min;
186     size_t m_max;
187 };
188
189 #define GCPHASE(name) DEFINE_GC_LOGGING_GLOBAL(GCTimer, name##Timer, (#name)); GCTimerScope name##TimerScope(&name##Timer, m_operationInProgress)
190 #define GCCOUNTER(name, value) do { DEFINE_GC_LOGGING_GLOBAL(GCCounter, name##Counter, (#name)); name##Counter.count(value); } while (false)
191     
192 #else
193
194 #define GCPHASE(name) do { } while (false)
195 #define GCCOUNTER(name, value) do { } while (false)
196 #endif
197
198 static inline size_t minHeapSize(HeapType heapType, size_t ramSize)
199 {
200     if (heapType == LargeHeap)
201         return min(largeHeapSize, ramSize / 4);
202     return smallHeapSize;
203 }
204
205 static inline size_t proportionalHeapSize(size_t heapSize, size_t ramSize)
206 {
207     // Try to stay under 1/2 RAM size to leave room for the DOM, rendering, networking, etc.
208     if (heapSize < ramSize / 4)
209         return 2 * heapSize;
210     if (heapSize < ramSize / 2)
211         return 1.5 * heapSize;
212     return 1.25 * heapSize;
213 }
214
215 static inline bool isValidSharedInstanceThreadState(VM* vm)
216 {
217     return vm->currentThreadIsHoldingAPILock();
218 }
219
220 static inline bool isValidThreadState(VM* vm)
221 {
222     if (vm->atomicStringTable() != wtfThreadData().atomicStringTable())
223         return false;
224
225     if (vm->isSharedInstance() && !isValidSharedInstanceThreadState(vm))
226         return false;
227
228     return true;
229 }
230
231 struct MarkObject : public MarkedBlock::VoidFunctor {
232     void operator()(JSCell* cell)
233     {
234         if (cell->isZapped())
235             return;
236         Heap::heap(cell)->setMarked(cell);
237     }
238 };
239
240 struct Count : public MarkedBlock::CountFunctor {
241     void operator()(JSCell*) { count(1); }
242 };
243
244 struct CountIfGlobalObject : MarkedBlock::CountFunctor {
245     void operator()(JSCell* cell) {
246         if (!cell->isObject())
247             return;
248         if (!asObject(cell)->isGlobalObject())
249             return;
250         count(1);
251     }
252 };
253
254 class RecordType {
255 public:
256     typedef PassOwnPtr<TypeCountSet> ReturnType;
257
258     RecordType();
259     void operator()(JSCell*);
260     ReturnType returnValue();
261
262 private:
263     const char* typeName(JSCell*);
264     OwnPtr<TypeCountSet> m_typeCountSet;
265 };
266
267 inline RecordType::RecordType()
268     : m_typeCountSet(adoptPtr(new TypeCountSet))
269 {
270 }
271
272 inline const char* RecordType::typeName(JSCell* cell)
273 {
274     const ClassInfo* info = cell->classInfo();
275     if (!info || !info->className)
276         return "[unknown]";
277     return info->className;
278 }
279
280 inline void RecordType::operator()(JSCell* cell)
281 {
282     m_typeCountSet->add(typeName(cell));
283 }
284
285 inline PassOwnPtr<TypeCountSet> RecordType::returnValue()
286 {
287     return m_typeCountSet.release();
288 }
289
290 } // anonymous namespace
291
292 Heap::Heap(VM* vm, HeapType heapType)
293     : m_heapType(heapType)
294     , m_ramSize(ramSize())
295     , m_minBytesPerCycle(minHeapSize(m_heapType, m_ramSize))
296     , m_sizeAfterLastCollect(0)
297     , m_sizeAfterLastFullCollect(0)
298     , m_sizeBeforeLastFullCollect(0)
299     , m_sizeAfterLastEdenCollect(0)
300     , m_sizeBeforeLastEdenCollect(0)
301     , m_bytesAllocatedThisCycle(0)
302     , m_bytesAbandonedSinceLastFullCollect(0)
303     , m_maxEdenSize(m_minBytesPerCycle)
304     , m_maxHeapSize(m_minBytesPerCycle)
305     , m_shouldDoFullCollection(false)
306     , m_totalBytesVisited(0)
307     , m_totalBytesCopied(0)
308     , m_operationInProgress(NoOperation)
309     , m_blockAllocator()
310     , m_objectSpace(this)
311     , m_storageSpace(this)
312     , m_extraMemoryUsage(0)
313     , m_machineThreads(this)
314     , m_sharedData(vm)
315     , m_slotVisitor(m_sharedData)
316     , m_copyVisitor(m_sharedData)
317     , m_handleSet(vm)
318     , m_codeBlocks(m_blockAllocator)
319     , m_isSafeToCollect(false)
320     , m_writeBarrierBuffer(256)
321     , m_vm(vm)
322     // We seed with 10ms so that GCActivityCallback::didAllocate doesn't continuously 
323     // schedule the timer if we've never done a collection.
324     , m_lastFullGCLength(0.01)
325     , m_lastEdenGCLength(0.01)
326     , m_lastCodeDiscardTime(WTF::monotonicallyIncreasingTime())
327     , m_fullActivityCallback(GCActivityCallback::createFullTimer(this))
328 #if ENABLE(GGC)
329     , m_edenActivityCallback(GCActivityCallback::createEdenTimer(this))
330 #else
331     , m_edenActivityCallback(m_fullActivityCallback)
332 #endif
333     , m_sweeper(IncrementalSweeper::create(this))
334     , m_deferralDepth(0)
335 {
336     m_storageSpace.init();
337 }
338
339 Heap::~Heap()
340 {
341 }
342
343 bool Heap::isPagedOut(double deadline)
344 {
345     return m_objectSpace.isPagedOut(deadline) || m_storageSpace.isPagedOut(deadline);
346 }
347
348 // The VM is being destroyed and the collector will never run again.
349 // Run all pending finalizers now because we won't get another chance.
350 void Heap::lastChanceToFinalize()
351 {
352     RELEASE_ASSERT(!m_vm->entryScope);
353     RELEASE_ASSERT(m_operationInProgress == NoOperation);
354
355     m_objectSpace.lastChanceToFinalize();
356 }
357
358 void Heap::reportExtraMemoryCostSlowCase(size_t cost)
359 {
360     // Our frequency of garbage collection tries to balance memory use against speed
361     // by collecting based on the number of newly created values. However, for values
362     // that hold on to a great deal of memory that's not in the form of other JS values,
363     // that is not good enough - in some cases a lot of those objects can pile up and
364     // use crazy amounts of memory without a GC happening. So we track these extra
365     // memory costs. Only unusually large objects are noted, and we only keep track
366     // of this extra cost until the next GC. In garbage collected languages, most values
367     // are either very short lived temporaries, or have extremely long lifetimes. So
368     // if a large value survives one garbage collection, there is not much point to
369     // collecting more frequently as long as it stays alive.
370
371     didAllocate(cost);
372     collectIfNecessaryOrDefer();
373 }
374
375 void Heap::reportAbandonedObjectGraph()
376 {
377     // Our clients don't know exactly how much memory they
378     // are abandoning so we just guess for them.
379     double abandonedBytes = 0.1 * m_sizeAfterLastCollect;
380
381     // We want to accelerate the next collection. Because memory has just 
382     // been abandoned, the next collection has the potential to 
383     // be more profitable. Since allocation is the trigger for collection, 
384     // we hasten the next collection by pretending that we've allocated more memory. 
385     didAbandon(abandonedBytes);
386 }
387
388 void Heap::didAbandon(size_t bytes)
389 {
390     if (m_fullActivityCallback) {
391         m_fullActivityCallback->didAllocate(
392             m_sizeAfterLastCollect - m_sizeAfterLastFullCollect + m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect);
393     }
394     m_bytesAbandonedSinceLastFullCollect += bytes;
395 }
396
397 void Heap::protect(JSValue k)
398 {
399     ASSERT(k);
400     ASSERT(m_vm->currentThreadIsHoldingAPILock());
401
402     if (!k.isCell())
403         return;
404
405     m_protectedValues.add(k.asCell());
406 }
407
408 bool Heap::unprotect(JSValue k)
409 {
410     ASSERT(k);
411     ASSERT(m_vm->currentThreadIsHoldingAPILock());
412
413     if (!k.isCell())
414         return false;
415
416     return m_protectedValues.remove(k.asCell());
417 }
418
419 void Heap::addReference(JSCell* cell, ArrayBuffer* buffer)
420 {
421     if (m_arrayBuffers.addReference(cell, buffer)) {
422         collectIfNecessaryOrDefer();
423         didAllocate(buffer->gcSizeEstimateInBytes());
424     }
425 }
426
427 void Heap::pushTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>* tempVector)
428 {
429     m_tempSortingVectors.append(tempVector);
430 }
431
432 void Heap::popTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>* tempVector)
433 {
434     ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last());
435     m_tempSortingVectors.removeLast();
436 }
437
438 void Heap::harvestWeakReferences()
439 {
440     m_slotVisitor.harvestWeakReferences();
441 }
442
443 void Heap::finalizeUnconditionalFinalizers()
444 {
445     GCPHASE(FinalizeUnconditionalFinalizers);
446     m_slotVisitor.finalizeUnconditionalFinalizers();
447 }
448
449 inline JSStack& Heap::stack()
450 {
451     return m_vm->interpreter->stack();
452 }
453
454 void Heap::willStartIterating()
455 {
456     m_objectSpace.willStartIterating();
457 }
458
459 void Heap::didFinishIterating()
460 {
461     m_objectSpace.didFinishIterating();
462 }
463
464 void Heap::getConservativeRegisterRoots(HashSet<JSCell*>& roots)
465 {
466     ASSERT(isValidThreadState(m_vm));
467     ConservativeRoots stackRoots(&m_objectSpace.blocks(), &m_storageSpace);
468     stack().gatherConservativeRoots(stackRoots);
469     size_t stackRootCount = stackRoots.size();
470     JSCell** registerRoots = stackRoots.roots();
471     for (size_t i = 0; i < stackRootCount; i++) {
472         setMarked(registerRoots[i]);
473         registerRoots[i]->setMarked();
474         roots.add(registerRoots[i]);
475     }
476 }
477
478 void Heap::markRoots(double gcStartTime)
479 {
480     SamplingRegion samplingRegion("Garbage Collection: Marking");
481
482     GCPHASE(MarkRoots);
483     ASSERT(isValidThreadState(m_vm));
484
485 #if ENABLE(GGC)
486     Vector<const JSCell*> rememberedSet(m_slotVisitor.markStack().size());
487     m_slotVisitor.markStack().fillVector(rememberedSet);
488 #else
489     Vector<const JSCell*> rememberedSet;
490 #endif
491
492     if (m_operationInProgress == EdenCollection)
493         m_codeBlocks.clearMarksForEdenCollection(rememberedSet);
494     else
495         m_codeBlocks.clearMarksForFullCollection();
496
497     // We gather conservative roots before clearing mark bits because conservative
498     // gathering uses the mark bits to determine whether a reference is valid.
499     void* dummy;
500     ConservativeRoots conservativeRoots(&m_objectSpace.blocks(), &m_storageSpace);
501     gatherStackRoots(conservativeRoots, &dummy);
502     gatherJSStackRoots(conservativeRoots);
503     gatherScratchBufferRoots(conservativeRoots);
504
505     sanitizeStackForVM(m_vm);
506
507     clearLivenessData();
508
509     m_sharedData.didStartMarking();
510     m_slotVisitor.didStartMarking();
511     HeapRootVisitor heapRootVisitor(m_slotVisitor);
512
513     {
514         ParallelModeEnabler enabler(m_slotVisitor);
515
516         visitExternalRememberedSet();
517         visitSmallStrings();
518         visitConservativeRoots(conservativeRoots);
519         visitCompilerWorklists();
520         visitProtectedObjects(heapRootVisitor);
521         visitTempSortVectors(heapRootVisitor);
522         visitArgumentBuffers(heapRootVisitor);
523         visitException(heapRootVisitor);
524         visitStrongHandles(heapRootVisitor);
525         visitHandleStack(heapRootVisitor);
526         traceCodeBlocksAndJITStubRoutines();
527         converge();
528     }
529
530     // Weak references must be marked last because their liveness depends on
531     // the liveness of the rest of the object graph.
532     visitWeakHandles(heapRootVisitor);
533
534     clearRememberedSet(rememberedSet);
535     m_sharedData.didFinishMarking();
536     updateObjectCounts(gcStartTime);
537     resetVisitors();
538 }
539
540 void Heap::copyBackingStores()
541 {
542     if (m_operationInProgress == EdenCollection)
543         m_storageSpace.startedCopying<EdenCollection>();
544     else {
545         ASSERT(m_operationInProgress == FullCollection);
546         m_storageSpace.startedCopying<FullCollection>();
547     }
548
549     if (m_storageSpace.shouldDoCopyPhase()) {
550         m_sharedData.didStartCopying();
551         m_copyVisitor.startCopying();
552         m_copyVisitor.copyFromShared();
553         m_copyVisitor.doneCopying();
554         // We need to wait for everybody to finish and return their CopiedBlocks 
555         // before signaling that the phase is complete.
556         m_storageSpace.doneCopying();
557         m_sharedData.didFinishCopying();
558     } else
559         m_storageSpace.doneCopying();
560 }
561
562 void Heap::gatherStackRoots(ConservativeRoots& roots, void** dummy)
563 {
564     GCPHASE(GatherStackRoots);
565     m_jitStubRoutines.clearMarks();
566     m_machineThreads.gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks, dummy);
567 }
568
569 void Heap::gatherJSStackRoots(ConservativeRoots& roots)
570 {
571 #if ENABLE(LLINT_C_LOOP)
572     GCPHASE(GatherJSStackRoots);
573     stack().gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks);
574 #else
575     UNUSED_PARAM(roots);
576 #endif
577 }
578
579 void Heap::gatherScratchBufferRoots(ConservativeRoots& roots)
580 {
581 #if ENABLE(DFG_JIT)
582     GCPHASE(GatherScratchBufferRoots);
583     m_vm->gatherConservativeRoots(roots);
584 #else
585     UNUSED_PARAM(roots);
586 #endif
587 }
588
589 void Heap::clearLivenessData()
590 {
591     GCPHASE(ClearLivenessData);
592     m_objectSpace.clearNewlyAllocated();
593     m_objectSpace.clearMarks();
594 }
595
596 void Heap::visitExternalRememberedSet()
597 {
598 #if JSC_OBJC_API_ENABLED
599     scanExternalRememberedSet(*m_vm, m_slotVisitor);
600 #endif
601 }
602
603 void Heap::visitSmallStrings()
604 {
605     GCPHASE(VisitSmallStrings);
606     m_vm->smallStrings.visitStrongReferences(m_slotVisitor);
607
608     if (Options::logGC() == GCLogging::Verbose)
609         dataLog("Small strings:\n", m_slotVisitor);
610
611     m_slotVisitor.donateAndDrain();
612 }
613
614 void Heap::visitConservativeRoots(ConservativeRoots& roots)
615 {
616     GCPHASE(VisitConservativeRoots);
617     m_slotVisitor.append(roots);
618
619     if (Options::logGC() == GCLogging::Verbose)
620         dataLog("Conservative Roots:\n", m_slotVisitor);
621
622     m_slotVisitor.donateAndDrain();
623 }
624
625 void Heap::visitCompilerWorklists()
626 {
627 #if ENABLE(DFG_JIT)
628     GCPHASE(VisitDFGWorklists);
629     for (unsigned i = DFG::numberOfWorklists(); i--;) {
630         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
631             worklist->visitChildren(m_slotVisitor, m_codeBlocks);
632     }
633
634     if (Options::logGC() == GCLogging::Verbose)
635         dataLog("DFG Worklists:\n", m_slotVisitor);
636
637     m_slotVisitor.donateAndDrain();
638 #endif
639 }
640
641 void Heap::visitProtectedObjects(HeapRootVisitor& heapRootVisitor)
642 {
643     GCPHASE(VisitProtectedObjects);
644
645     for (auto& pair : m_protectedValues)
646         heapRootVisitor.visit(&pair.key);
647
648     if (Options::logGC() == GCLogging::Verbose)
649         dataLog("Protected Objects:\n", m_slotVisitor);
650
651     m_slotVisitor.donateAndDrain();
652 }
653
654 void Heap::visitTempSortVectors(HeapRootVisitor& heapRootVisitor)
655 {
656     GCPHASE(VisitTempSortVectors);
657     typedef Vector<Vector<ValueStringPair, 0, UnsafeVectorOverflow>*> VectorOfValueStringVectors;
658
659     for (auto* vector : m_tempSortingVectors) {
660         for (auto& valueStringPair : *vector) {
661             if (valueStringPair.first)
662                 heapRootVisitor.visit(&valueStringPair.first);
663         }
664     }
665
666     if (Options::logGC() == GCLogging::Verbose)
667         dataLog("Temp Sort Vectors:\n", m_slotVisitor);
668
669     m_slotVisitor.donateAndDrain();
670 }
671
672 void Heap::visitArgumentBuffers(HeapRootVisitor& visitor)
673 {
674     GCPHASE(MarkingArgumentBuffers);
675     if (!m_markListSet || !m_markListSet->size())
676         return;
677
678     MarkedArgumentBuffer::markLists(visitor, *m_markListSet);
679
680     if (Options::logGC() == GCLogging::Verbose)
681         dataLog("Argument Buffers:\n", m_slotVisitor);
682
683     m_slotVisitor.donateAndDrain();
684 }
685
686 void Heap::visitException(HeapRootVisitor& visitor)
687 {
688     GCPHASE(MarkingException);
689     if (!m_vm->exception())
690         return;
691
692     visitor.visit(m_vm->addressOfException());
693
694     if (Options::logGC() == GCLogging::Verbose)
695         dataLog("Exceptions:\n", m_slotVisitor);
696
697     m_slotVisitor.donateAndDrain();
698 }
699
700 void Heap::visitStrongHandles(HeapRootVisitor& visitor)
701 {
702     GCPHASE(VisitStrongHandles);
703     m_handleSet.visitStrongHandles(visitor);
704
705     if (Options::logGC() == GCLogging::Verbose)
706         dataLog("Strong Handles:\n", m_slotVisitor);
707
708     m_slotVisitor.donateAndDrain();
709 }
710
711 void Heap::visitHandleStack(HeapRootVisitor& visitor)
712 {
713     GCPHASE(VisitHandleStack);
714     m_handleStack.visit(visitor);
715
716     if (Options::logGC() == GCLogging::Verbose)
717         dataLog("Handle Stack:\n", m_slotVisitor);
718
719     m_slotVisitor.donateAndDrain();
720 }
721
722 void Heap::traceCodeBlocksAndJITStubRoutines()
723 {
724     GCPHASE(TraceCodeBlocksAndJITStubRoutines);
725     m_codeBlocks.traceMarked(m_slotVisitor);
726     m_jitStubRoutines.traceMarkedStubRoutines(m_slotVisitor);
727
728     if (Options::logGC() == GCLogging::Verbose)
729         dataLog("Code Blocks and JIT Stub Routines:\n", m_slotVisitor);
730
731     m_slotVisitor.donateAndDrain();
732 }
733
734 void Heap::converge()
735 {
736 #if ENABLE(PARALLEL_GC)
737     GCPHASE(Convergence);
738     m_slotVisitor.drainFromShared(SlotVisitor::MasterDrain);
739 #endif
740 }
741
742 void Heap::visitWeakHandles(HeapRootVisitor& visitor)
743 {
744     GCPHASE(VisitingLiveWeakHandles);
745     while (true) {
746         m_objectSpace.visitWeakSets(visitor);
747         harvestWeakReferences();
748         if (m_slotVisitor.isEmpty())
749             break;
750
751         if (Options::logGC() == GCLogging::Verbose)
752             dataLog("Live Weak Handles:\n", m_slotVisitor);
753
754         {
755             ParallelModeEnabler enabler(m_slotVisitor);
756             m_slotVisitor.donateAndDrain();
757 #if ENABLE(PARALLEL_GC)
758             m_slotVisitor.drainFromShared(SlotVisitor::MasterDrain);
759 #endif
760         }
761     }
762 }
763
764 void Heap::clearRememberedSet(Vector<const JSCell*>& rememberedSet)
765 {
766 #if ENABLE(GGC)
767     GCPHASE(ClearRememberedSet);
768     for (auto* cell : rememberedSet) {
769         MarkedBlock::blockFor(cell)->clearRemembered(cell);
770         const_cast<JSCell*>(cell)->setRemembered(false);
771     }
772 #else
773     UNUSED_PARAM(rememberedSet);
774 #endif
775 }
776
777 void Heap::updateObjectCounts(double gcStartTime)
778 {
779     GCCOUNTER(VisitedValueCount, m_slotVisitor.visitCount());
780
781     if (Options::logGC() == GCLogging::Verbose) {
782         size_t visitCount = m_slotVisitor.visitCount();
783 #if ENABLE(PARALLEL_GC)
784         visitCount += m_sharedData.childVisitCount();
785 #endif
786         dataLogF("\nNumber of live Objects after GC %lu, took %.6f secs\n", static_cast<unsigned long>(visitCount), WTF::monotonicallyIncreasingTime() - gcStartTime);
787     }
788
789     if (m_operationInProgress == EdenCollection) {
790         m_totalBytesVisited += m_slotVisitor.bytesVisited();
791         m_totalBytesCopied += m_slotVisitor.bytesCopied();
792     } else {
793         ASSERT(m_operationInProgress == FullCollection);
794         m_totalBytesVisited = m_slotVisitor.bytesVisited();
795         m_totalBytesCopied = m_slotVisitor.bytesCopied();
796     }
797 #if ENABLE(PARALLEL_GC)
798     m_totalBytesVisited += m_sharedData.childBytesVisited();
799     m_totalBytesCopied += m_sharedData.childBytesCopied();
800 #endif
801 }
802
803 void Heap::resetVisitors()
804 {
805     m_slotVisitor.reset();
806 #if ENABLE(PARALLEL_GC)
807     m_sharedData.resetChildren();
808 #endif
809     m_sharedData.reset();
810 }
811
812 size_t Heap::objectCount()
813 {
814     return m_objectSpace.objectCount();
815 }
816
817 size_t Heap::extraSize()
818 {
819     return m_extraMemoryUsage + m_arrayBuffers.size();
820 }
821
822 size_t Heap::size()
823 {
824     return m_objectSpace.size() + m_storageSpace.size() + extraSize();
825 }
826
827 size_t Heap::capacity()
828 {
829     return m_objectSpace.capacity() + m_storageSpace.capacity() + extraSize();
830 }
831
832 size_t Heap::sizeAfterCollect()
833 {
834     // The result here may not agree with the normal Heap::size(). 
835     // This is due to the fact that we only count live copied bytes
836     // rather than all used (including dead) copied bytes, thus it's 
837     // always the case that m_totalBytesCopied <= m_storageSpace.size(). 
838     ASSERT(m_totalBytesCopied <= m_storageSpace.size());
839     return m_totalBytesVisited + m_totalBytesCopied + extraSize();
840 }
841
842 size_t Heap::protectedGlobalObjectCount()
843 {
844     return forEachProtectedCell<CountIfGlobalObject>();
845 }
846
847 size_t Heap::globalObjectCount()
848 {
849     HeapIterationScope iterationScope(*this);
850     return m_objectSpace.forEachLiveCell<CountIfGlobalObject>(iterationScope);
851 }
852
853 size_t Heap::protectedObjectCount()
854 {
855     return forEachProtectedCell<Count>();
856 }
857
858 PassOwnPtr<TypeCountSet> Heap::protectedObjectTypeCounts()
859 {
860     return forEachProtectedCell<RecordType>();
861 }
862
863 PassOwnPtr<TypeCountSet> Heap::objectTypeCounts()
864 {
865     HeapIterationScope iterationScope(*this);
866     return m_objectSpace.forEachLiveCell<RecordType>(iterationScope);
867 }
868
869 void Heap::deleteAllCompiledCode()
870 {
871     // If JavaScript is running, it's not safe to delete code, since we'll end
872     // up deleting code that is live on the stack.
873     if (m_vm->entryScope)
874         return;
875     
876     // If we have things on any worklist, then don't delete code. This is kind of
877     // a weird heuristic. It's definitely not safe to throw away code that is on
878     // the worklist. But this change was made in a hurry so we just avoid throwing
879     // away any code if there is any code on any worklist. I suspect that this
880     // might not actually be too dumb: if there is code on worklists then that
881     // means that we are running some hot JS code right now. Maybe causing
882     // recompilations isn't a good idea.
883 #if ENABLE(DFG_JIT)
884     for (unsigned i = DFG::numberOfWorklists(); i--;) {
885         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
886             if (worklist->isActiveForVM(*vm()))
887                 return;
888         }
889     }
890 #endif // ENABLE(DFG_JIT)
891
892     for (ExecutableBase* current = m_compiledCode.head(); current; current = current->next()) {
893         if (!current->isFunctionExecutable())
894             continue;
895         static_cast<FunctionExecutable*>(current)->clearCodeIfNotCompiling();
896     }
897
898     ASSERT(m_operationInProgress == FullCollection || m_operationInProgress == NoOperation);
899     m_codeBlocks.clearMarksForFullCollection();
900     m_codeBlocks.deleteUnmarkedAndUnreferenced(FullCollection);
901 }
902
903 void Heap::deleteAllUnlinkedFunctionCode()
904 {
905     for (ExecutableBase* current = m_compiledCode.head(); current; current = current->next()) {
906         if (!current->isFunctionExecutable())
907             continue;
908         static_cast<FunctionExecutable*>(current)->clearUnlinkedCodeForRecompilationIfNotCompiling();
909     }
910 }
911
912 void Heap::clearUnmarkedExecutables()
913 {
914     GCPHASE(ClearUnmarkedExecutables);
915     ExecutableBase* next;
916     for (ExecutableBase* current = m_compiledCode.head(); current; current = next) {
917         next = current->next();
918         if (isMarked(current))
919             continue;
920
921         // We do this because executable memory is limited on some platforms and because
922         // CodeBlock requires eager finalization.
923         ExecutableBase::clearCodeVirtual(current);
924         m_compiledCode.remove(current);
925     }
926 }
927
928 void Heap::deleteUnmarkedCompiledCode()
929 {
930     GCPHASE(DeleteCodeBlocks);
931     clearUnmarkedExecutables();
932     m_codeBlocks.deleteUnmarkedAndUnreferenced(m_operationInProgress);
933     m_jitStubRoutines.deleteUnmarkedJettisonedStubRoutines();
934 }
935
936 void Heap::addToRememberedSet(const JSCell* cell)
937 {
938     ASSERT(cell);
939     ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread());
940     if (isRemembered(cell))
941         return;
942     MarkedBlock::blockFor(cell)->setRemembered(cell);
943     const_cast<JSCell*>(cell)->setRemembered(true);
944     m_slotVisitor.unconditionallyAppend(const_cast<JSCell*>(cell));
945 }
946
947 void Heap::collectAllGarbage()
948 {
949     if (!m_isSafeToCollect)
950         return;
951
952     collect(FullCollection);
953
954     SamplingRegion samplingRegion("Garbage Collection: Sweeping");
955     DelayedReleaseScope delayedReleaseScope(m_objectSpace);
956     m_objectSpace.sweep();
957     m_objectSpace.shrink();
958 }
959
960 static double minute = 60.0;
961
962 void Heap::collect(HeapOperation collectionType)
963 {
964 #if ENABLE(ALLOCATION_LOGGING)
965     dataLogF("JSC GC starting collection.\n");
966 #endif
967     
968     double before = 0;
969     if (Options::logGC()) {
970         dataLog("[GC: ");
971         before = currentTimeMS();
972     }
973     
974     SamplingRegion samplingRegion("Garbage Collection");
975     
976     RELEASE_ASSERT(!m_deferralDepth);
977     ASSERT(vm()->currentThreadIsHoldingAPILock());
978     RELEASE_ASSERT(vm()->atomicStringTable() == wtfThreadData().atomicStringTable());
979     ASSERT(m_isSafeToCollect);
980     JAVASCRIPTCORE_GC_BEGIN();
981     RELEASE_ASSERT(m_operationInProgress == NoOperation);
982
983     suspendCompilerThreads();
984     willStartCollection(collectionType);
985     GCPHASE(Collect);
986
987     double gcStartTime = WTF::monotonicallyIncreasingTime();
988
989     deleteOldCode(gcStartTime);
990     flushOldStructureIDTables();
991     stopAllocation();
992     flushWriteBarrierBuffer();
993
994     markRoots(gcStartTime);
995
996     JAVASCRIPTCORE_GC_MARKED();
997
998     reapWeakHandles();
999     sweepArrayBuffers();
1000     snapshotMarkedSpace();
1001
1002     copyBackingStores();
1003
1004     finalizeUnconditionalFinalizers();
1005     deleteUnmarkedCompiledCode();
1006     deleteSourceProviderCaches();
1007     notifyIncrementalSweeper();
1008     rememberCurrentlyExecutingCodeBlocks();
1009
1010     resetAllocators();
1011     updateAllocationLimits();
1012     didFinishCollection(gcStartTime);
1013     resumeCompilerThreads();
1014
1015     if (Options::logGC()) {
1016         double after = currentTimeMS();
1017         dataLog(after - before, " ms]\n");
1018     }
1019 }
1020
1021 void Heap::suspendCompilerThreads()
1022 {
1023 #if ENABLE(DFG_JIT)
1024     GCPHASE(SuspendCompilerThreads);
1025     for (unsigned i = DFG::numberOfWorklists(); i--;) {
1026         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
1027             worklist->suspendAllThreads();
1028     }
1029 #endif
1030 }
1031
1032 void Heap::willStartCollection(HeapOperation collectionType)
1033 {
1034     GCPHASE(StartingCollection);
1035     if (shouldDoFullCollection(collectionType)) {
1036         m_operationInProgress = FullCollection;
1037         m_slotVisitor.clearMarkStack();
1038         m_shouldDoFullCollection = false;
1039         if (Options::logGC())
1040             dataLog("FullCollection, ");
1041     } else {
1042         m_operationInProgress = EdenCollection;
1043         if (Options::logGC())
1044             dataLog("EdenCollection, ");
1045     }
1046     if (m_operationInProgress == FullCollection) {
1047         m_sizeBeforeLastFullCollect = m_sizeAfterLastCollect + m_bytesAllocatedThisCycle;
1048         m_extraMemoryUsage = 0;
1049
1050         if (m_fullActivityCallback)
1051             m_fullActivityCallback->willCollect();
1052     } else {
1053         ASSERT(m_operationInProgress == EdenCollection);
1054         m_sizeBeforeLastEdenCollect = m_sizeAfterLastCollect + m_bytesAllocatedThisCycle;
1055     }
1056
1057     if (m_edenActivityCallback)
1058         m_edenActivityCallback->willCollect();
1059 }
1060
1061 void Heap::deleteOldCode(double gcStartTime)
1062 {
1063     if (m_operationInProgress == EdenCollection)
1064         return;
1065
1066     GCPHASE(DeleteOldCode);
1067     if (gcStartTime - m_lastCodeDiscardTime > minute) {
1068         deleteAllCompiledCode();
1069         m_lastCodeDiscardTime = WTF::monotonicallyIncreasingTime();
1070     }
1071 }
1072
1073 void Heap::flushOldStructureIDTables()
1074 {
1075     GCPHASE(FlushOldStructureIDTables);
1076     m_structureIDTable.flushOldTables();
1077 }
1078
1079 void Heap::flushWriteBarrierBuffer()
1080 {
1081     GCPHASE(FlushWriteBarrierBuffer);
1082     if (m_operationInProgress == EdenCollection) {
1083         m_writeBarrierBuffer.flush(*this);
1084         return;
1085     }
1086     m_writeBarrierBuffer.reset();
1087 }
1088
1089 void Heap::stopAllocation()
1090 {
1091     GCPHASE(StopAllocation);
1092     m_objectSpace.stopAllocating();
1093     if (m_operationInProgress == FullCollection)
1094         m_storageSpace.didStartFullCollection();
1095 }
1096
1097 void Heap::reapWeakHandles()
1098 {
1099     GCPHASE(ReapingWeakHandles);
1100     m_objectSpace.reapWeakSets();
1101 }
1102
1103 void Heap::sweepArrayBuffers()
1104 {
1105     GCPHASE(SweepingArrayBuffers);
1106     m_arrayBuffers.sweep();
1107 }
1108
1109 struct MarkedBlockSnapshotFunctor : public MarkedBlock::VoidFunctor {
1110     MarkedBlockSnapshotFunctor(Vector<MarkedBlock*>& blocks) 
1111         : m_index(0) 
1112         , m_blocks(blocks)
1113     {
1114     }
1115
1116     void operator()(MarkedBlock* block) { m_blocks[m_index++] = block; }
1117
1118     size_t m_index;
1119     Vector<MarkedBlock*>& m_blocks;
1120 };
1121
1122 void Heap::snapshotMarkedSpace()
1123 {
1124     GCPHASE(SnapshotMarkedSpace);
1125     if (m_operationInProgress != FullCollection)
1126         return;
1127
1128     m_blockSnapshot.resize(m_objectSpace.blocks().set().size());
1129     MarkedBlockSnapshotFunctor functor(m_blockSnapshot);
1130     m_objectSpace.forEachBlock(functor);
1131 }
1132
1133 void Heap::deleteSourceProviderCaches()
1134 {
1135     GCPHASE(DeleteSourceProviderCaches);
1136     m_vm->clearSourceProviderCaches();
1137 }
1138
1139 void Heap::notifyIncrementalSweeper()
1140 {
1141     GCPHASE(NotifyIncrementalSweeper);
1142     if (m_operationInProgress != FullCollection)
1143         return;
1144     m_sweeper->startSweeping(m_blockSnapshot);
1145 }
1146
1147 void Heap::rememberCurrentlyExecutingCodeBlocks()
1148 {
1149     GCPHASE(RememberCurrentlyExecutingCodeBlocks);
1150     m_codeBlocks.rememberCurrentlyExecutingCodeBlocks(this);
1151 }
1152
1153 void Heap::resetAllocators()
1154 {
1155     GCPHASE(ResetAllocators);
1156     m_objectSpace.resetAllocators();
1157 }
1158
1159 void Heap::updateAllocationLimits()
1160 {
1161     GCPHASE(UpdateAllocationLimits);
1162     size_t currentHeapSize = sizeAfterCollect();
1163     if (Options::gcMaxHeapSize() && currentHeapSize > Options::gcMaxHeapSize())
1164         HeapStatistics::exitWithFailure();
1165
1166     if (m_operationInProgress == FullCollection) {
1167         // To avoid pathological GC churn in very small and very large heaps, we set
1168         // the new allocation limit based on the current size of the heap, with a
1169         // fixed minimum.
1170         m_maxHeapSize = max(minHeapSize(m_heapType, m_ramSize), proportionalHeapSize(currentHeapSize, m_ramSize));
1171         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
1172         m_sizeAfterLastFullCollect = currentHeapSize;
1173         m_bytesAbandonedSinceLastFullCollect = 0;
1174     } else {
1175         ASSERT(currentHeapSize >= m_sizeAfterLastCollect);
1176         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
1177         m_sizeAfterLastEdenCollect = currentHeapSize;
1178         double edenToOldGenerationRatio = (double)m_maxEdenSize / (double)m_maxHeapSize;
1179         double minEdenToOldGenerationRatio = 1.0 / 3.0;
1180         if (edenToOldGenerationRatio < minEdenToOldGenerationRatio)
1181             m_shouldDoFullCollection = true;
1182         m_maxHeapSize += currentHeapSize - m_sizeAfterLastCollect;
1183         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
1184         if (m_fullActivityCallback) {
1185             ASSERT(currentHeapSize >= m_sizeAfterLastFullCollect);
1186             m_fullActivityCallback->didAllocate(currentHeapSize - m_sizeAfterLastFullCollect);
1187         }
1188     }
1189
1190     m_sizeAfterLastCollect = currentHeapSize;
1191     m_bytesAllocatedThisCycle = 0;
1192
1193     if (Options::logGC())
1194         dataLog(currentHeapSize / 1024, " kb, ");
1195 }
1196
1197 void Heap::didFinishCollection(double gcStartTime)
1198 {
1199     GCPHASE(FinishingCollection);
1200     double gcEndTime = WTF::monotonicallyIncreasingTime();
1201     if (m_operationInProgress == FullCollection)
1202         m_lastFullGCLength = gcEndTime - gcStartTime;
1203     else
1204         m_lastEdenGCLength = gcEndTime - gcStartTime;
1205
1206     if (Options::recordGCPauseTimes())
1207         HeapStatistics::recordGCPauseTime(gcStartTime, gcEndTime);
1208     RELEASE_ASSERT(m_operationInProgress == EdenCollection || m_operationInProgress == FullCollection);
1209
1210     m_operationInProgress = NoOperation;
1211     JAVASCRIPTCORE_GC_END();
1212
1213     if (Options::useZombieMode())
1214         zombifyDeadObjects();
1215
1216     if (Options::objectsAreImmortal())
1217         markDeadObjects();
1218
1219     if (Options::showObjectStatistics())
1220         HeapStatistics::showObjectStatistics(this);
1221
1222     if (Options::logGC() == GCLogging::Verbose)
1223         GCLogging::dumpObjectGraph(this);
1224 }
1225
1226 void Heap::resumeCompilerThreads()
1227 {
1228 #if ENABLE(DFG_JIT)
1229     GCPHASE(ResumeCompilerThreads);
1230     for (unsigned i = DFG::numberOfWorklists(); i--;) {
1231         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
1232             worklist->resumeAllThreads();
1233     }
1234 #endif
1235 }
1236
1237 void Heap::markDeadObjects()
1238 {
1239     HeapIterationScope iterationScope(*this);
1240     m_objectSpace.forEachDeadCell<MarkObject>(iterationScope);
1241 }
1242
1243 void Heap::setFullActivityCallback(PassRefPtr<FullGCActivityCallback> activityCallback)
1244 {
1245     m_fullActivityCallback = activityCallback;
1246 }
1247
1248 void Heap::setEdenActivityCallback(PassRefPtr<EdenGCActivityCallback> activityCallback)
1249 {
1250     m_edenActivityCallback = activityCallback;
1251 }
1252
1253 GCActivityCallback* Heap::fullActivityCallback()
1254 {
1255     return m_fullActivityCallback.get();
1256 }
1257
1258 GCActivityCallback* Heap::edenActivityCallback()
1259 {
1260     return m_edenActivityCallback.get();
1261 }
1262
1263 void Heap::setIncrementalSweeper(PassOwnPtr<IncrementalSweeper> sweeper)
1264 {
1265     m_sweeper = sweeper;
1266 }
1267
1268 IncrementalSweeper* Heap::sweeper()
1269 {
1270     return m_sweeper.get();
1271 }
1272
1273 void Heap::setGarbageCollectionTimerEnabled(bool enable)
1274 {
1275     if (m_fullActivityCallback)
1276         m_fullActivityCallback->setEnabled(enable);
1277     if (m_edenActivityCallback)
1278         m_edenActivityCallback->setEnabled(enable);
1279 }
1280
1281 void Heap::didAllocate(size_t bytes)
1282 {
1283     if (m_edenActivityCallback)
1284         m_edenActivityCallback->didAllocate(m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect);
1285     m_bytesAllocatedThisCycle += bytes;
1286 }
1287
1288 bool Heap::isValidAllocation(size_t)
1289 {
1290     if (!isValidThreadState(m_vm))
1291         return false;
1292
1293     if (m_operationInProgress != NoOperation)
1294         return false;
1295     
1296     return true;
1297 }
1298
1299 void Heap::addFinalizer(JSCell* cell, Finalizer finalizer)
1300 {
1301     WeakSet::allocate(cell, &m_finalizerOwner, reinterpret_cast<void*>(finalizer)); // Balanced by FinalizerOwner::finalize().
1302 }
1303
1304 void Heap::FinalizerOwner::finalize(Handle<Unknown> handle, void* context)
1305 {
1306     HandleSlot slot = handle.slot();
1307     Finalizer finalizer = reinterpret_cast<Finalizer>(context);
1308     finalizer(slot->asCell());
1309     WeakSet::deallocate(WeakImpl::asWeakImpl(slot));
1310 }
1311
1312 void Heap::addCompiledCode(ExecutableBase* executable)
1313 {
1314     m_compiledCode.append(executable);
1315 }
1316
1317 class Zombify : public MarkedBlock::VoidFunctor {
1318 public:
1319     void operator()(JSCell* cell)
1320     {
1321         void** current = reinterpret_cast<void**>(cell);
1322
1323         // We want to maintain zapped-ness because that's how we know if we've called 
1324         // the destructor.
1325         if (cell->isZapped())
1326             current++;
1327
1328         void* limit = static_cast<void*>(reinterpret_cast<char*>(cell) + MarkedBlock::blockFor(cell)->cellSize());
1329         for (; current < limit; current++)
1330             *current = reinterpret_cast<void*>(0xbbadbeef);
1331     }
1332 };
1333
1334 void Heap::zombifyDeadObjects()
1335 {
1336     // Sweep now because destructors will crash once we're zombified.
1337     m_objectSpace.sweep();
1338     HeapIterationScope iterationScope(*this);
1339     m_objectSpace.forEachDeadCell<Zombify>(iterationScope);
1340 }
1341
1342 void Heap::flushWriteBarrierBuffer(JSCell* cell)
1343 {
1344 #if ENABLE(GGC)
1345     m_writeBarrierBuffer.flush(*this);
1346     m_writeBarrierBuffer.add(cell);
1347 #else
1348     UNUSED_PARAM(cell);
1349 #endif
1350 }
1351
1352 bool Heap::shouldDoFullCollection(HeapOperation requestedCollectionType) const
1353 {
1354 #if ENABLE(GGC)
1355     if (Options::alwaysDoFullCollection())
1356         return true;
1357
1358     switch (requestedCollectionType) {
1359     case EdenCollection:
1360         return false;
1361     case FullCollection:
1362         return true;
1363     case AnyCollection:
1364         return m_shouldDoFullCollection;
1365     default:
1366         RELEASE_ASSERT_NOT_REACHED();
1367         return false;
1368     }
1369     RELEASE_ASSERT_NOT_REACHED();
1370     return false;
1371 #else
1372     UNUSED_PARAM(requestedCollectionType);
1373     return true;
1374 #endif
1375 }
1376
1377 } // namespace JSC