Allow one sync GC per gcTimer interval on critical memory pressure warning
[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         const_cast<JSCell*>(cell)->setRemembered(false);
803 #else
804     UNUSED_PARAM(rememberedSet);
805 #endif
806 }
807
808 void Heap::updateObjectCounts(double gcStartTime)
809 {
810     GCCOUNTER(VisitedValueCount, m_slotVisitor.visitCount());
811
812     if (Options::logGC() == GCLogging::Verbose) {
813         size_t visitCount = m_slotVisitor.visitCount();
814 #if ENABLE(PARALLEL_GC)
815         visitCount += m_sharedData.childVisitCount();
816 #endif
817         dataLogF("\nNumber of live Objects after GC %lu, took %.6f secs\n", static_cast<unsigned long>(visitCount), WTF::monotonicallyIncreasingTime() - gcStartTime);
818     }
819     
820     size_t bytesRemovedFromOldSpaceDueToReallocation =
821         m_storageSpace.takeBytesRemovedFromOldSpaceDueToReallocation();
822     
823     if (m_operationInProgress == FullCollection) {
824         m_totalBytesVisited = 0;
825         m_totalBytesCopied = 0;
826     } else
827         m_totalBytesCopied -= bytesRemovedFromOldSpaceDueToReallocation;
828     
829     m_totalBytesVisited += m_slotVisitor.bytesVisited();
830     m_totalBytesCopied += m_slotVisitor.bytesCopied();
831 #if ENABLE(PARALLEL_GC)
832     m_totalBytesVisited += m_sharedData.childBytesVisited();
833     m_totalBytesCopied += m_sharedData.childBytesCopied();
834 #endif
835 }
836
837 void Heap::resetVisitors()
838 {
839     m_slotVisitor.reset();
840 #if ENABLE(PARALLEL_GC)
841     m_sharedData.resetChildren();
842 #endif
843     m_sharedData.reset();
844 }
845
846 size_t Heap::objectCount()
847 {
848     return m_objectSpace.objectCount();
849 }
850
851 size_t Heap::extraMemorySize()
852 {
853     return m_extraMemorySize + m_deprecatedExtraMemorySize + m_arrayBuffers.size();
854 }
855
856 size_t Heap::size()
857 {
858     return m_objectSpace.size() + m_storageSpace.size() + extraMemorySize();
859 }
860
861 size_t Heap::capacity()
862 {
863     return m_objectSpace.capacity() + m_storageSpace.capacity() + extraMemorySize();
864 }
865
866 size_t Heap::sizeAfterCollect()
867 {
868     // The result here may not agree with the normal Heap::size(). 
869     // This is due to the fact that we only count live copied bytes
870     // rather than all used (including dead) copied bytes, thus it's 
871     // always the case that m_totalBytesCopied <= m_storageSpace.size(). 
872     ASSERT(m_totalBytesCopied <= m_storageSpace.size());
873     return m_totalBytesVisited + m_totalBytesCopied + extraMemorySize();
874 }
875
876 size_t Heap::protectedGlobalObjectCount()
877 {
878     return forEachProtectedCell<CountIfGlobalObject>();
879 }
880
881 size_t Heap::globalObjectCount()
882 {
883     HeapIterationScope iterationScope(*this);
884     return m_objectSpace.forEachLiveCell<CountIfGlobalObject>(iterationScope);
885 }
886
887 size_t Heap::protectedObjectCount()
888 {
889     return forEachProtectedCell<Count>();
890 }
891
892 std::unique_ptr<TypeCountSet> Heap::protectedObjectTypeCounts()
893 {
894     return forEachProtectedCell<RecordType>();
895 }
896
897 std::unique_ptr<TypeCountSet> Heap::objectTypeCounts()
898 {
899     HeapIterationScope iterationScope(*this);
900     return m_objectSpace.forEachLiveCell<RecordType>(iterationScope);
901 }
902
903 void Heap::deleteAllCompiledCode()
904 {
905     // If JavaScript is running, it's not safe to delete code, since we'll end
906     // up deleting code that is live on the stack.
907     if (m_vm->entryScope)
908         return;
909     
910     // If we have things on any worklist, then don't delete code. This is kind of
911     // a weird heuristic. It's definitely not safe to throw away code that is on
912     // the worklist. But this change was made in a hurry so we just avoid throwing
913     // away any code if there is any code on any worklist. I suspect that this
914     // might not actually be too dumb: if there is code on worklists then that
915     // means that we are running some hot JS code right now. Maybe causing
916     // recompilations isn't a good idea.
917 #if ENABLE(DFG_JIT)
918     for (unsigned i = DFG::numberOfWorklists(); i--;) {
919         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
920             if (worklist->isActiveForVM(*vm()))
921                 return;
922         }
923     }
924 #endif // ENABLE(DFG_JIT)
925
926     for (ExecutableBase* current : m_compiledCode) {
927         if (!current->isFunctionExecutable())
928             continue;
929         static_cast<FunctionExecutable*>(current)->clearCode();
930     }
931
932     ASSERT(m_operationInProgress == FullCollection || m_operationInProgress == NoOperation);
933     m_codeBlocks.clearMarksForFullCollection();
934     m_codeBlocks.deleteUnmarkedAndUnreferenced(FullCollection);
935 }
936
937 void Heap::deleteAllUnlinkedFunctionCode()
938 {
939     for (ExecutableBase* current : m_compiledCode) {
940         if (!current->isFunctionExecutable())
941             continue;
942         static_cast<FunctionExecutable*>(current)->clearUnlinkedCodeForRecompilation();
943     }
944 }
945
946 void Heap::clearUnmarkedExecutables()
947 {
948     GCPHASE(ClearUnmarkedExecutables);
949     for (unsigned i = m_compiledCode.size(); i--;) {
950         ExecutableBase* current = m_compiledCode[i];
951         if (isMarked(current))
952             continue;
953
954         // We do this because executable memory is limited on some platforms and because
955         // CodeBlock requires eager finalization.
956         ExecutableBase::clearCodeVirtual(current);
957         std::swap(m_compiledCode[i], m_compiledCode.last());
958         m_compiledCode.removeLast();
959     }
960 }
961
962 void Heap::deleteUnmarkedCompiledCode()
963 {
964     GCPHASE(DeleteCodeBlocks);
965     clearUnmarkedExecutables();
966     m_codeBlocks.deleteUnmarkedAndUnreferenced(m_operationInProgress);
967     m_jitStubRoutines.deleteUnmarkedJettisonedStubRoutines();
968 }
969
970 void Heap::addToRememberedSet(const JSCell* cell)
971 {
972     ASSERT(cell);
973     ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread());
974     if (isRemembered(cell))
975         return;
976     const_cast<JSCell*>(cell)->setRemembered(true);
977     m_slotVisitor.unconditionallyAppend(const_cast<JSCell*>(cell));
978 }
979
980 void Heap::collectAndSweep(HeapOperation collectionType)
981 {
982     if (!m_isSafeToCollect)
983         return;
984
985     collect(collectionType);
986
987     SamplingRegion samplingRegion("Garbage Collection: Sweeping");
988
989     DeferGCForAWhile deferGC(*this);
990     m_objectSpace.sweep();
991     m_objectSpace.shrink();
992
993     sweepAllLogicallyEmptyWeakBlocks();
994 }
995
996 static double minute = 60.0;
997
998 NEVER_INLINE void Heap::collect(HeapOperation collectionType)
999 {
1000     void* stackTop;
1001     ALLOCATE_AND_GET_REGISTER_STATE(registers);
1002
1003     collectImpl(collectionType, wtfThreadData().stack().origin(), &stackTop, registers);
1004
1005     sanitizeStackForVM(m_vm);
1006 }
1007
1008 NEVER_INLINE void Heap::collectImpl(HeapOperation collectionType, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters)
1009 {
1010 #if ENABLE(ALLOCATION_LOGGING)
1011     dataLogF("JSC GC starting collection.\n");
1012 #endif
1013     
1014     double before = 0;
1015     if (Options::logGC()) {
1016         dataLog("[GC: ");
1017         before = currentTimeMS();
1018     }
1019     
1020     SamplingRegion samplingRegion("Garbage Collection");
1021     
1022     if (vm()->typeProfiler()) {
1023         DeferGCForAWhile awhile(*this);
1024         vm()->typeProfilerLog()->processLogEntries(ASCIILiteral("GC"));
1025     }
1026     
1027     RELEASE_ASSERT(!m_deferralDepth);
1028     ASSERT(vm()->currentThreadIsHoldingAPILock());
1029     RELEASE_ASSERT(vm()->atomicStringTable() == wtfThreadData().atomicStringTable());
1030     ASSERT(m_isSafeToCollect);
1031     JAVASCRIPTCORE_GC_BEGIN();
1032     RELEASE_ASSERT(m_operationInProgress == NoOperation);
1033
1034     suspendCompilerThreads();
1035     willStartCollection(collectionType);
1036     GCPHASE(Collect);
1037
1038     double gcStartTime = WTF::monotonicallyIncreasingTime();
1039     if (m_verifier) {
1040         // Verify that live objects from the last GC cycle haven't been corrupted by
1041         // mutators before we begin this new GC cycle.
1042         m_verifier->verify(HeapVerifier::Phase::BeforeGC);
1043
1044         m_verifier->initializeGCCycle();
1045         m_verifier->gatherLiveObjects(HeapVerifier::Phase::BeforeMarking);
1046     }
1047
1048     deleteOldCode(gcStartTime);
1049     flushOldStructureIDTables();
1050     stopAllocation();
1051     flushWriteBarrierBuffer();
1052
1053     markRoots(gcStartTime, stackOrigin, stackTop, calleeSavedRegisters);
1054
1055     if (m_verifier) {
1056         m_verifier->gatherLiveObjects(HeapVerifier::Phase::AfterMarking);
1057         m_verifier->verify(HeapVerifier::Phase::AfterMarking);
1058     }
1059     JAVASCRIPTCORE_GC_MARKED();
1060
1061     if (vm()->typeProfiler())
1062         vm()->typeProfiler()->invalidateTypeSetCache();
1063
1064     reapWeakHandles();
1065     pruneStaleEntriesFromWeakGCMaps();
1066     sweepArrayBuffers();
1067     snapshotMarkedSpace();
1068
1069     copyBackingStores();
1070
1071     finalizeUnconditionalFinalizers();
1072     removeDeadCompilerWorklistEntries();
1073     deleteUnmarkedCompiledCode();
1074     deleteSourceProviderCaches();
1075     notifyIncrementalSweeper();
1076     rememberCurrentlyExecutingCodeBlocks();
1077
1078     resetAllocators();
1079     updateAllocationLimits();
1080     didFinishCollection(gcStartTime);
1081     resumeCompilerThreads();
1082
1083     if (m_verifier) {
1084         m_verifier->trimDeadObjects();
1085         m_verifier->verify(HeapVerifier::Phase::AfterGC);
1086     }
1087
1088     if (Options::logGC()) {
1089         double after = currentTimeMS();
1090         dataLog(after - before, " ms]\n");
1091     }
1092 }
1093
1094 void Heap::suspendCompilerThreads()
1095 {
1096 #if ENABLE(DFG_JIT)
1097     GCPHASE(SuspendCompilerThreads);
1098     ASSERT(m_suspendedCompilerWorklists.isEmpty());
1099     for (unsigned i = DFG::numberOfWorklists(); i--;) {
1100         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
1101             m_suspendedCompilerWorklists.append(worklist);
1102             worklist->suspendAllThreads();
1103         }
1104     }
1105 #endif
1106 }
1107
1108 void Heap::willStartCollection(HeapOperation collectionType)
1109 {
1110     GCPHASE(StartingCollection);
1111     if (shouldDoFullCollection(collectionType)) {
1112         m_operationInProgress = FullCollection;
1113         m_slotVisitor.clearMarkStack();
1114         m_shouldDoFullCollection = false;
1115         if (Options::logGC())
1116             dataLog("FullCollection, ");
1117     } else {
1118         m_operationInProgress = EdenCollection;
1119         if (Options::logGC())
1120             dataLog("EdenCollection, ");
1121     }
1122     if (m_operationInProgress == FullCollection) {
1123         m_sizeBeforeLastFullCollect = m_sizeAfterLastCollect + m_bytesAllocatedThisCycle;
1124         m_extraMemorySize = 0;
1125         m_deprecatedExtraMemorySize = 0;
1126
1127         if (m_fullActivityCallback)
1128             m_fullActivityCallback->willCollect();
1129     } else {
1130         ASSERT(m_operationInProgress == EdenCollection);
1131         m_sizeBeforeLastEdenCollect = m_sizeAfterLastCollect + m_bytesAllocatedThisCycle;
1132     }
1133
1134     if (m_edenActivityCallback)
1135         m_edenActivityCallback->willCollect();
1136 }
1137
1138 void Heap::deleteOldCode(double gcStartTime)
1139 {
1140     if (m_operationInProgress == EdenCollection)
1141         return;
1142
1143     GCPHASE(DeleteOldCode);
1144     if (gcStartTime - m_lastCodeDiscardTime > minute) {
1145         deleteAllCompiledCode();
1146         m_lastCodeDiscardTime = WTF::monotonicallyIncreasingTime();
1147     }
1148 }
1149
1150 void Heap::flushOldStructureIDTables()
1151 {
1152     GCPHASE(FlushOldStructureIDTables);
1153     m_structureIDTable.flushOldTables();
1154 }
1155
1156 void Heap::flushWriteBarrierBuffer()
1157 {
1158     GCPHASE(FlushWriteBarrierBuffer);
1159     if (m_operationInProgress == EdenCollection) {
1160         m_writeBarrierBuffer.flush(*this);
1161         return;
1162     }
1163     m_writeBarrierBuffer.reset();
1164 }
1165
1166 void Heap::stopAllocation()
1167 {
1168     GCPHASE(StopAllocation);
1169     m_objectSpace.stopAllocating();
1170     if (m_operationInProgress == FullCollection)
1171         m_storageSpace.didStartFullCollection();
1172 }
1173
1174 void Heap::reapWeakHandles()
1175 {
1176     GCPHASE(ReapingWeakHandles);
1177     m_objectSpace.reapWeakSets();
1178 }
1179
1180 void Heap::pruneStaleEntriesFromWeakGCMaps()
1181 {
1182     GCPHASE(PruningStaleEntriesFromWeakGCMaps);
1183     if (m_operationInProgress != FullCollection)
1184         return;
1185     for (auto& pruneCallback : m_weakGCMaps.values())
1186         pruneCallback();
1187 }
1188
1189 void Heap::sweepArrayBuffers()
1190 {
1191     GCPHASE(SweepingArrayBuffers);
1192     m_arrayBuffers.sweep();
1193 }
1194
1195 struct MarkedBlockSnapshotFunctor : public MarkedBlock::VoidFunctor {
1196     MarkedBlockSnapshotFunctor(Vector<MarkedBlock*>& blocks) 
1197         : m_index(0) 
1198         , m_blocks(blocks)
1199     {
1200     }
1201
1202     void operator()(MarkedBlock* block) { m_blocks[m_index++] = block; }
1203
1204     size_t m_index;
1205     Vector<MarkedBlock*>& m_blocks;
1206 };
1207
1208 void Heap::snapshotMarkedSpace()
1209 {
1210     GCPHASE(SnapshotMarkedSpace);
1211
1212     if (m_operationInProgress == EdenCollection) {
1213         m_blockSnapshot.appendVector(m_objectSpace.blocksWithNewObjects());
1214         // Sort and deduplicate the block snapshot since we might be appending to an unfinished work list.
1215         std::sort(m_blockSnapshot.begin(), m_blockSnapshot.end());
1216         m_blockSnapshot.shrink(std::unique(m_blockSnapshot.begin(), m_blockSnapshot.end()) - m_blockSnapshot.begin());
1217     } else {
1218         m_blockSnapshot.resizeToFit(m_objectSpace.blocks().set().size());
1219         MarkedBlockSnapshotFunctor functor(m_blockSnapshot);
1220         m_objectSpace.forEachBlock(functor);
1221     }
1222 }
1223
1224 void Heap::deleteSourceProviderCaches()
1225 {
1226     GCPHASE(DeleteSourceProviderCaches);
1227     m_vm->clearSourceProviderCaches();
1228 }
1229
1230 void Heap::notifyIncrementalSweeper()
1231 {
1232     GCPHASE(NotifyIncrementalSweeper);
1233
1234     if (m_operationInProgress == FullCollection) {
1235         if (!m_logicallyEmptyWeakBlocks.isEmpty())
1236             m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0;
1237     }
1238
1239     m_sweeper->startSweeping();
1240 }
1241
1242 void Heap::rememberCurrentlyExecutingCodeBlocks()
1243 {
1244     GCPHASE(RememberCurrentlyExecutingCodeBlocks);
1245     m_codeBlocks.rememberCurrentlyExecutingCodeBlocks(this);
1246 }
1247
1248 void Heap::resetAllocators()
1249 {
1250     GCPHASE(ResetAllocators);
1251     m_objectSpace.resetAllocators();
1252 }
1253
1254 void Heap::updateAllocationLimits()
1255 {
1256     GCPHASE(UpdateAllocationLimits);
1257     size_t currentHeapSize = sizeAfterCollect();
1258     if (Options::gcMaxHeapSize() && currentHeapSize > Options::gcMaxHeapSize())
1259         HeapStatistics::exitWithFailure();
1260
1261     if (m_operationInProgress == FullCollection) {
1262         // To avoid pathological GC churn in very small and very large heaps, we set
1263         // the new allocation limit based on the current size of the heap, with a
1264         // fixed minimum.
1265         m_maxHeapSize = max(minHeapSize(m_heapType, m_ramSize), proportionalHeapSize(currentHeapSize, m_ramSize));
1266         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
1267         m_sizeAfterLastFullCollect = currentHeapSize;
1268         m_bytesAbandonedSinceLastFullCollect = 0;
1269     } else {
1270         ASSERT(currentHeapSize >= m_sizeAfterLastCollect);
1271         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
1272         m_sizeAfterLastEdenCollect = currentHeapSize;
1273         double edenToOldGenerationRatio = (double)m_maxEdenSize / (double)m_maxHeapSize;
1274         double minEdenToOldGenerationRatio = 1.0 / 3.0;
1275         if (edenToOldGenerationRatio < minEdenToOldGenerationRatio)
1276             m_shouldDoFullCollection = true;
1277         m_maxHeapSize += currentHeapSize - m_sizeAfterLastCollect;
1278         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
1279         if (m_fullActivityCallback) {
1280             ASSERT(currentHeapSize >= m_sizeAfterLastFullCollect);
1281             m_fullActivityCallback->didAllocate(currentHeapSize - m_sizeAfterLastFullCollect);
1282         }
1283     }
1284
1285     m_sizeAfterLastCollect = currentHeapSize;
1286     m_bytesAllocatedThisCycle = 0;
1287
1288     if (Options::logGC())
1289         dataLog(currentHeapSize / 1024, " kb, ");
1290 }
1291
1292 void Heap::didFinishCollection(double gcStartTime)
1293 {
1294     GCPHASE(FinishingCollection);
1295     double gcEndTime = WTF::monotonicallyIncreasingTime();
1296     if (m_operationInProgress == FullCollection)
1297         m_lastFullGCLength = gcEndTime - gcStartTime;
1298     else
1299         m_lastEdenGCLength = gcEndTime - gcStartTime;
1300
1301     if (Options::recordGCPauseTimes())
1302         HeapStatistics::recordGCPauseTime(gcStartTime, gcEndTime);
1303
1304     if (Options::useZombieMode())
1305         zombifyDeadObjects();
1306
1307     if (Options::objectsAreImmortal())
1308         markDeadObjects();
1309
1310     if (Options::showObjectStatistics())
1311         HeapStatistics::showObjectStatistics(this);
1312
1313     if (Options::logGC() == GCLogging::Verbose)
1314         GCLogging::dumpObjectGraph(this);
1315
1316     RELEASE_ASSERT(m_operationInProgress == EdenCollection || m_operationInProgress == FullCollection);
1317     m_operationInProgress = NoOperation;
1318     JAVASCRIPTCORE_GC_END();
1319 }
1320
1321 void Heap::resumeCompilerThreads()
1322 {
1323 #if ENABLE(DFG_JIT)
1324     GCPHASE(ResumeCompilerThreads);
1325     for (auto worklist : m_suspendedCompilerWorklists)
1326         worklist->resumeAllThreads();
1327     m_suspendedCompilerWorklists.clear();
1328 #endif
1329 }
1330
1331 void Heap::markDeadObjects()
1332 {
1333     HeapIterationScope iterationScope(*this);
1334     m_objectSpace.forEachDeadCell<MarkObject>(iterationScope);
1335 }
1336
1337 void Heap::setFullActivityCallback(PassRefPtr<FullGCActivityCallback> activityCallback)
1338 {
1339     m_fullActivityCallback = activityCallback;
1340 }
1341
1342 void Heap::setEdenActivityCallback(PassRefPtr<EdenGCActivityCallback> activityCallback)
1343 {
1344     m_edenActivityCallback = activityCallback;
1345 }
1346
1347 GCActivityCallback* Heap::fullActivityCallback()
1348 {
1349     return m_fullActivityCallback.get();
1350 }
1351
1352 GCActivityCallback* Heap::edenActivityCallback()
1353 {
1354     return m_edenActivityCallback.get();
1355 }
1356
1357 void Heap::setIncrementalSweeper(std::unique_ptr<IncrementalSweeper> sweeper)
1358 {
1359     m_sweeper = WTF::move(sweeper);
1360 }
1361
1362 IncrementalSweeper* Heap::sweeper()
1363 {
1364     return m_sweeper.get();
1365 }
1366
1367 void Heap::setGarbageCollectionTimerEnabled(bool enable)
1368 {
1369     if (m_fullActivityCallback)
1370         m_fullActivityCallback->setEnabled(enable);
1371     if (m_edenActivityCallback)
1372         m_edenActivityCallback->setEnabled(enable);
1373 }
1374
1375 void Heap::didAllocate(size_t bytes)
1376 {
1377     if (m_edenActivityCallback)
1378         m_edenActivityCallback->didAllocate(m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect);
1379     m_bytesAllocatedThisCycle += bytes;
1380 }
1381
1382 bool Heap::isValidAllocation(size_t)
1383 {
1384     if (!isValidThreadState(m_vm))
1385         return false;
1386
1387     if (m_operationInProgress != NoOperation)
1388         return false;
1389     
1390     return true;
1391 }
1392
1393 void Heap::addFinalizer(JSCell* cell, Finalizer finalizer)
1394 {
1395     WeakSet::allocate(cell, &m_finalizerOwner, reinterpret_cast<void*>(finalizer)); // Balanced by FinalizerOwner::finalize().
1396 }
1397
1398 void Heap::FinalizerOwner::finalize(Handle<Unknown> handle, void* context)
1399 {
1400     HandleSlot slot = handle.slot();
1401     Finalizer finalizer = reinterpret_cast<Finalizer>(context);
1402     finalizer(slot->asCell());
1403     WeakSet::deallocate(WeakImpl::asWeakImpl(slot));
1404 }
1405
1406 void Heap::addCompiledCode(ExecutableBase* executable)
1407 {
1408     m_compiledCode.append(executable);
1409 }
1410
1411 void Heap::collectAllGarbageIfNotDoneRecently()
1412 {
1413     if (!m_fullActivityCallback) {
1414         collectAllGarbage();
1415         return;
1416     }
1417
1418     if (m_fullActivityCallback->didSyncGCRecently()) {
1419         // A synchronous GC was already requested recently so we merely accelerate next collection.
1420         reportAbandonedObjectGraph();
1421         return;
1422     }
1423
1424     m_fullActivityCallback->setDidSyncGCRecently();
1425     collectAllGarbage();
1426 }
1427
1428 class Zombify : public MarkedBlock::VoidFunctor {
1429 public:
1430     inline void visit(JSCell* cell)
1431     {
1432         void** current = reinterpret_cast<void**>(cell);
1433
1434         // We want to maintain zapped-ness because that's how we know if we've called 
1435         // the destructor.
1436         if (cell->isZapped())
1437             current++;
1438
1439         void* limit = static_cast<void*>(reinterpret_cast<char*>(cell) + MarkedBlock::blockFor(cell)->cellSize());
1440         for (; current < limit; current++)
1441             *current = zombifiedBits;
1442     }
1443     IterationStatus operator()(JSCell* cell)
1444     {
1445         visit(cell);
1446         return IterationStatus::Continue;
1447     }
1448 };
1449
1450 void Heap::zombifyDeadObjects()
1451 {
1452     // Sweep now because destructors will crash once we're zombified.
1453     {
1454         SamplingRegion samplingRegion("Garbage Collection: Sweeping");
1455         m_objectSpace.zombifySweep();
1456     }
1457     HeapIterationScope iterationScope(*this);
1458     m_objectSpace.forEachDeadCell<Zombify>(iterationScope);
1459 }
1460
1461 void Heap::flushWriteBarrierBuffer(JSCell* cell)
1462 {
1463 #if ENABLE(GGC)
1464     m_writeBarrierBuffer.flush(*this);
1465     m_writeBarrierBuffer.add(cell);
1466 #else
1467     UNUSED_PARAM(cell);
1468 #endif
1469 }
1470
1471 bool Heap::shouldDoFullCollection(HeapOperation requestedCollectionType) const
1472 {
1473 #if ENABLE(GGC)
1474     if (Options::alwaysDoFullCollection())
1475         return true;
1476
1477     switch (requestedCollectionType) {
1478     case EdenCollection:
1479         return false;
1480     case FullCollection:
1481         return true;
1482     case AnyCollection:
1483         return m_shouldDoFullCollection;
1484     default:
1485         RELEASE_ASSERT_NOT_REACHED();
1486         return false;
1487     }
1488     RELEASE_ASSERT_NOT_REACHED();
1489     return false;
1490 #else
1491     UNUSED_PARAM(requestedCollectionType);
1492     return true;
1493 #endif
1494 }
1495
1496 void Heap::addLogicallyEmptyWeakBlock(WeakBlock* block)
1497 {
1498     m_logicallyEmptyWeakBlocks.append(block);
1499 }
1500
1501 void Heap::sweepAllLogicallyEmptyWeakBlocks()
1502 {
1503     if (m_logicallyEmptyWeakBlocks.isEmpty())
1504         return;
1505
1506     m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0;
1507     while (sweepNextLogicallyEmptyWeakBlock()) { }
1508 }
1509
1510 bool Heap::sweepNextLogicallyEmptyWeakBlock()
1511 {
1512     if (m_indexOfNextLogicallyEmptyWeakBlockToSweep == WTF::notFound)
1513         return false;
1514
1515     WeakBlock* block = m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep];
1516
1517     block->sweep();
1518     if (block->isEmpty()) {
1519         std::swap(m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep], m_logicallyEmptyWeakBlocks.last());
1520         m_logicallyEmptyWeakBlocks.removeLast();
1521         WeakBlock::destroy(block);
1522     } else
1523         m_indexOfNextLogicallyEmptyWeakBlockToSweep++;
1524
1525     if (m_indexOfNextLogicallyEmptyWeakBlockToSweep >= m_logicallyEmptyWeakBlocks.size()) {
1526         m_indexOfNextLogicallyEmptyWeakBlockToSweep = WTF::notFound;
1527         return false;
1528     }
1529
1530     return true;
1531 }
1532
1533 } // namespace JSC