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