5a805ae2c7270520195c348d7324e34ec6ff888d
[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 "RegExpCache.h"
47 #include "Tracing.h"
48 #include "TypeProfilerLog.h"
49 #include "UnlinkedCodeBlock.h"
50 #include "VM.h"
51 #include "WeakSetInlines.h"
52 #include <algorithm>
53 #include <wtf/RAMSize.h>
54 #include <wtf/CurrentTime.h>
55 #include <wtf/ProcessID.h>
56
57 using namespace std;
58 using namespace JSC;
59
60 namespace JSC {
61
62 namespace { 
63
64 static const size_t largeHeapSize = 32 * MB; // About 1.5X the average webpage.
65 static const size_t smallHeapSize = 1 * MB; // Matches the FastMalloc per-thread cache.
66
67 #define ENABLE_GC_LOGGING 0
68
69 #if ENABLE(GC_LOGGING)
70 #if COMPILER(CLANG)
71 #define DEFINE_GC_LOGGING_GLOBAL(type, name, arguments) \
72 _Pragma("clang diagnostic push") \
73 _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \
74 _Pragma("clang diagnostic ignored \"-Wexit-time-destructors\"") \
75 static type name arguments; \
76 _Pragma("clang diagnostic pop")
77 #else
78 #define DEFINE_GC_LOGGING_GLOBAL(type, name, arguments) \
79 static type name arguments;
80 #endif // COMPILER(CLANG)
81
82 struct GCTimer {
83     GCTimer(const char* name)
84         : name(name)
85     {
86     }
87     ~GCTimer()
88     {
89         logData(allCollectionData, "(All)");
90         logData(edenCollectionData, "(Eden)");
91         logData(fullCollectionData, "(Full)");
92     }
93
94     struct TimeRecord {
95         TimeRecord()
96             : time(0)
97             , min(std::numeric_limits<double>::infinity())
98             , max(0)
99             , count(0)
100         {
101         }
102
103         double time;
104         double min;
105         double max;
106         size_t count;
107     };
108
109     void logData(const TimeRecord& data, const char* extra)
110     {
111         dataLogF("[%d] %s (Parent: %s) %s: %.2lfms (avg. %.2lf, min. %.2lf, max. %.2lf, count %lu)\n", 
112             getCurrentProcessID(),
113             name,
114             parent ? parent->name : "nullptr",
115             extra, 
116             data.time * 1000, 
117             data.time * 1000 / data.count, 
118             data.min * 1000, 
119             data.max * 1000,
120             data.count);
121     }
122
123     void updateData(TimeRecord& data, double duration)
124     {
125         if (duration < data.min)
126             data.min = duration;
127         if (duration > data.max)
128             data.max = duration;
129         data.count++;
130         data.time += duration;
131     }
132
133     void didFinishPhase(HeapOperation collectionType, double duration)
134     {
135         TimeRecord& data = collectionType == EdenCollection ? edenCollectionData : fullCollectionData;
136         updateData(data, duration);
137         updateData(allCollectionData, duration);
138     }
139
140     static GCTimer* s_currentGlobalTimer;
141
142     TimeRecord allCollectionData;
143     TimeRecord fullCollectionData;
144     TimeRecord edenCollectionData;
145     const char* name;
146     GCTimer* parent { nullptr };
147 };
148
149 GCTimer* GCTimer::s_currentGlobalTimer = nullptr;
150
151 struct GCTimerScope {
152     GCTimerScope(GCTimer& timer, HeapOperation collectionType)
153         : timer(timer)
154         , start(WTF::monotonicallyIncreasingTime())
155         , collectionType(collectionType)
156     {
157         timer.parent = GCTimer::s_currentGlobalTimer;
158         GCTimer::s_currentGlobalTimer = &timer;
159     }
160     ~GCTimerScope()
161     {
162         double delta = WTF::monotonicallyIncreasingTime() - start;
163         timer.didFinishPhase(collectionType, delta);
164         GCTimer::s_currentGlobalTimer = timer.parent;
165     }
166     GCTimer& timer;
167     double start;
168     HeapOperation collectionType;
169 };
170
171 struct GCCounter {
172     GCCounter(const char* name)
173         : name(name)
174         , count(0)
175         , total(0)
176         , min(10000000)
177         , max(0)
178     {
179     }
180     
181     void add(size_t amount)
182     {
183         count++;
184         total += amount;
185         if (amount < min)
186             min = amount;
187         if (amount > max)
188             max = amount;
189     }
190     ~GCCounter()
191     {
192         dataLogF("[%d] %s: %zu values (avg. %zu, min. %zu, max. %zu)\n", getCurrentProcessID(), name, total, total / count, min, max);
193     }
194     const char* name;
195     size_t count;
196     size_t total;
197     size_t min;
198     size_t max;
199 };
200
201 #define GCPHASE(name) DEFINE_GC_LOGGING_GLOBAL(GCTimer, name##Timer, (#name)); GCTimerScope name##TimerScope(name##Timer, m_operationInProgress)
202 #define GCCOUNTER(name, value) do { DEFINE_GC_LOGGING_GLOBAL(GCCounter, name##Counter, (#name)); name##Counter.add(value); } while (false)
203     
204 #else
205
206 #define GCPHASE(name) do { } while (false)
207 #define GCCOUNTER(name, value) do { } while (false)
208 #endif
209
210 static inline size_t minHeapSize(HeapType heapType, size_t ramSize)
211 {
212     if (heapType == LargeHeap)
213         return min(largeHeapSize, ramSize / 4);
214     return smallHeapSize;
215 }
216
217 static inline size_t proportionalHeapSize(size_t heapSize, size_t ramSize)
218 {
219     // Try to stay under 1/2 RAM size to leave room for the DOM, rendering, networking, etc.
220     if (heapSize < ramSize / 4)
221         return 2 * heapSize;
222     if (heapSize < ramSize / 2)
223         return 1.5 * heapSize;
224     return 1.25 * heapSize;
225 }
226
227 static inline bool isValidSharedInstanceThreadState(VM* vm)
228 {
229     return vm->currentThreadIsHoldingAPILock();
230 }
231
232 static inline bool isValidThreadState(VM* vm)
233 {
234     if (vm->atomicStringTable() != wtfThreadData().atomicStringTable())
235         return false;
236
237     if (vm->isSharedInstance() && !isValidSharedInstanceThreadState(vm))
238         return false;
239
240     return true;
241 }
242
243 struct MarkObject : public MarkedBlock::VoidFunctor {
244     inline void visit(JSCell* cell)
245     {
246         if (cell->isZapped())
247             return;
248         Heap::heap(cell)->setMarked(cell);
249     }
250     IterationStatus operator()(JSCell* cell)
251     {
252         visit(cell);
253         return IterationStatus::Continue;
254     }
255 };
256
257 struct Count : public MarkedBlock::CountFunctor {
258     void operator()(JSCell*) { count(1); }
259 };
260
261 struct CountIfGlobalObject : MarkedBlock::CountFunctor {
262     inline void visit(JSCell* cell)
263     {
264         if (!cell->isObject())
265             return;
266         if (!asObject(cell)->isGlobalObject())
267             return;
268         count(1);
269     }
270     IterationStatus operator()(JSCell* cell)
271     {
272         visit(cell);
273         return IterationStatus::Continue;
274     }
275 };
276
277 class RecordType {
278 public:
279     typedef std::unique_ptr<TypeCountSet> ReturnType;
280
281     RecordType();
282     IterationStatus operator()(JSCell*);
283     ReturnType returnValue();
284
285 private:
286     const char* typeName(JSCell*);
287     std::unique_ptr<TypeCountSet> m_typeCountSet;
288 };
289
290 inline RecordType::RecordType()
291     : m_typeCountSet(std::make_unique<TypeCountSet>())
292 {
293 }
294
295 inline const char* RecordType::typeName(JSCell* cell)
296 {
297     const ClassInfo* info = cell->classInfo();
298     if (!info || !info->className)
299         return "[unknown]";
300     return info->className;
301 }
302
303 inline IterationStatus RecordType::operator()(JSCell* cell)
304 {
305     m_typeCountSet->add(typeName(cell));
306     return IterationStatus::Continue;
307 }
308
309 inline std::unique_ptr<TypeCountSet> RecordType::returnValue()
310 {
311     return WTF::move(m_typeCountSet);
312 }
313
314 } // anonymous namespace
315
316 Heap::Heap(VM* vm, HeapType heapType)
317     : m_heapType(heapType)
318     , m_ramSize(Options::forceRAMSize() ? Options::forceRAMSize() : ramSize())
319     , m_minBytesPerCycle(minHeapSize(m_heapType, m_ramSize))
320     , m_sizeAfterLastCollect(0)
321     , m_sizeAfterLastFullCollect(0)
322     , m_sizeBeforeLastFullCollect(0)
323     , m_sizeAfterLastEdenCollect(0)
324     , m_sizeBeforeLastEdenCollect(0)
325     , m_bytesAllocatedThisCycle(0)
326     , m_bytesAbandonedSinceLastFullCollect(0)
327     , m_maxEdenSize(m_minBytesPerCycle)
328     , m_maxHeapSize(m_minBytesPerCycle)
329     , m_shouldDoFullCollection(false)
330     , m_totalBytesVisited(0)
331     , m_totalBytesCopied(0)
332     , m_operationInProgress(NoOperation)
333     , m_objectSpace(this)
334     , m_storageSpace(this)
335     , m_extraMemorySize(0)
336     , m_deprecatedExtraMemorySize(0)
337     , m_machineThreads(this)
338     , m_sharedData(vm)
339     , m_slotVisitor(m_sharedData)
340     , m_copyVisitor(m_sharedData)
341     , m_handleSet(vm)
342     , m_isSafeToCollect(false)
343     , m_writeBarrierBuffer(256)
344     , m_vm(vm)
345     // We seed with 10ms so that GCActivityCallback::didAllocate doesn't continuously 
346     // schedule the timer if we've never done a collection.
347     , m_lastFullGCLength(0.01)
348     , m_lastEdenGCLength(0.01)
349     , m_lastCodeDiscardTime(WTF::monotonicallyIncreasingTime())
350     , m_fullActivityCallback(GCActivityCallback::createFullTimer(this))
351 #if ENABLE(GGC)
352     , m_edenActivityCallback(GCActivityCallback::createEdenTimer(this))
353 #else
354     , m_edenActivityCallback(m_fullActivityCallback)
355 #endif
356 #if USE(CF)
357     , m_sweeper(std::make_unique<IncrementalSweeper>(this, CFRunLoopGetCurrent()))
358 #else
359     , m_sweeper(std::make_unique<IncrementalSweeper>(this->vm()))
360 #endif
361     , m_deferralDepth(0)
362 #if USE(CF)
363     , m_delayedReleaseRecursionCount(0)
364 #endif
365 {
366     m_storageSpace.init();
367     if (Options::verifyHeap())
368         m_verifier = std::make_unique<HeapVerifier>(this, Options::numberOfGCCyclesToRecordForVerification());
369 }
370
371 Heap::~Heap()
372 {
373     for (WeakBlock* block : m_logicallyEmptyWeakBlocks)
374         WeakBlock::destroy(block);
375 }
376
377 bool Heap::isPagedOut(double deadline)
378 {
379     return m_objectSpace.isPagedOut(deadline) || m_storageSpace.isPagedOut(deadline);
380 }
381
382 // The VM is being destroyed and the collector will never run again.
383 // Run all pending finalizers now because we won't get another chance.
384 void Heap::lastChanceToFinalize()
385 {
386     RELEASE_ASSERT(!m_vm->entryScope);
387     RELEASE_ASSERT(m_operationInProgress == NoOperation);
388
389     m_objectSpace.lastChanceToFinalize();
390     releaseDelayedReleasedObjects();
391
392     sweepAllLogicallyEmptyWeakBlocks();
393 }
394
395 void Heap::releaseDelayedReleasedObjects()
396 {
397 #if USE(CF)
398     // We need to guard against the case that releasing an object can create more objects due to the
399     // release calling into JS. When those JS call(s) exit and all locks are being dropped we end up
400     // back here and could try to recursively release objects. We guard that with a recursive entry
401     // count. Only the initial call will release objects, recursive calls simple return and let the
402     // the initial call to the function take care of any objects created during release time.
403     // This also means that we need to loop until there are no objects in m_delayedReleaseObjects
404     // and use a temp Vector for the actual releasing.
405     if (!m_delayedReleaseRecursionCount++) {
406         while (!m_delayedReleaseObjects.isEmpty()) {
407             ASSERT(m_vm->currentThreadIsHoldingAPILock());
408
409             Vector<RetainPtr<CFTypeRef>> objectsToRelease = WTF::move(m_delayedReleaseObjects);
410
411             {
412                 // We need to drop locks before calling out to arbitrary code.
413                 JSLock::DropAllLocks dropAllLocks(m_vm);
414
415                 objectsToRelease.clear();
416             }
417         }
418     }
419     m_delayedReleaseRecursionCount--;
420 #endif
421 }
422
423 void Heap::reportExtraMemoryAllocatedSlowCase(size_t size)
424 {
425     didAllocate(size);
426     collectIfNecessaryOrDefer();
427 }
428
429 void Heap::deprecatedReportExtraMemorySlowCase(size_t size)
430 {
431     m_deprecatedExtraMemorySize += size;
432     reportExtraMemoryAllocatedSlowCase(size);
433 }
434
435 void Heap::reportAbandonedObjectGraph()
436 {
437     // Our clients don't know exactly how much memory they
438     // are abandoning so we just guess for them.
439     double abandonedBytes = 0.1 * m_sizeAfterLastCollect;
440
441     // We want to accelerate the next collection. Because memory has just 
442     // been abandoned, the next collection has the potential to 
443     // be more profitable. Since allocation is the trigger for collection, 
444     // we hasten the next collection by pretending that we've allocated more memory. 
445     didAbandon(abandonedBytes);
446 }
447
448 void Heap::didAbandon(size_t bytes)
449 {
450     if (m_fullActivityCallback) {
451         m_fullActivityCallback->didAllocate(
452             m_sizeAfterLastCollect - m_sizeAfterLastFullCollect + m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect);
453     }
454     m_bytesAbandonedSinceLastFullCollect += bytes;
455 }
456
457 void Heap::protect(JSValue k)
458 {
459     ASSERT(k);
460     ASSERT(m_vm->currentThreadIsHoldingAPILock());
461
462     if (!k.isCell())
463         return;
464
465     m_protectedValues.add(k.asCell());
466 }
467
468 bool Heap::unprotect(JSValue k)
469 {
470     ASSERT(k);
471     ASSERT(m_vm->currentThreadIsHoldingAPILock());
472
473     if (!k.isCell())
474         return false;
475
476     return m_protectedValues.remove(k.asCell());
477 }
478
479 void Heap::addReference(JSCell* cell, ArrayBuffer* buffer)
480 {
481     if (m_arrayBuffers.addReference(cell, buffer)) {
482         collectIfNecessaryOrDefer();
483         didAllocate(buffer->gcSizeEstimateInBytes());
484     }
485 }
486
487 void Heap::harvestWeakReferences()
488 {
489     m_slotVisitor.harvestWeakReferences();
490 }
491
492 void Heap::finalizeUnconditionalFinalizers()
493 {
494     GCPHASE(FinalizeUnconditionalFinalizers);
495     m_slotVisitor.finalizeUnconditionalFinalizers();
496 }
497
498 inline JSStack& Heap::stack()
499 {
500     return m_vm->interpreter->stack();
501 }
502
503 void Heap::willStartIterating()
504 {
505     m_objectSpace.willStartIterating();
506 }
507
508 void Heap::didFinishIterating()
509 {
510     m_objectSpace.didFinishIterating();
511 }
512
513 void Heap::getConservativeRegisterRoots(HashSet<JSCell*>& roots)
514 {
515     ASSERT(isValidThreadState(m_vm));
516     ConservativeRoots stackRoots(&m_objectSpace.blocks(), &m_storageSpace);
517     stack().gatherConservativeRoots(stackRoots);
518     size_t stackRootCount = stackRoots.size();
519     JSCell** registerRoots = stackRoots.roots();
520     for (size_t i = 0; i < stackRootCount; i++) {
521         setMarked(registerRoots[i]);
522         registerRoots[i]->setMarked();
523         roots.add(registerRoots[i]);
524     }
525 }
526
527 void Heap::markRoots(double gcStartTime, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters)
528 {
529     SamplingRegion samplingRegion("Garbage Collection: Marking");
530
531     GCPHASE(MarkRoots);
532     ASSERT(isValidThreadState(m_vm));
533
534 #if ENABLE(GGC)
535     Vector<const JSCell*> rememberedSet(m_slotVisitor.markStack().size());
536     m_slotVisitor.markStack().fillVector(rememberedSet);
537 #else
538     Vector<const JSCell*> rememberedSet;
539 #endif
540
541     if (m_operationInProgress == EdenCollection)
542         m_codeBlocks.clearMarksForEdenCollection(rememberedSet);
543     else
544         m_codeBlocks.clearMarksForFullCollection();
545
546     // We gather conservative roots before clearing mark bits because conservative
547     // gathering uses the mark bits to determine whether a reference is valid.
548     ConservativeRoots conservativeRoots(&m_objectSpace.blocks(), &m_storageSpace);
549     gatherStackRoots(conservativeRoots, stackOrigin, stackTop, calleeSavedRegisters);
550     gatherJSStackRoots(conservativeRoots);
551     gatherScratchBufferRoots(conservativeRoots);
552
553     clearLivenessData();
554
555     m_sharedData.didStartMarking();
556     m_slotVisitor.didStartMarking();
557     HeapRootVisitor heapRootVisitor(m_slotVisitor);
558
559     {
560         ParallelModeEnabler enabler(m_slotVisitor);
561
562         visitExternalRememberedSet();
563         visitSmallStrings();
564         visitConservativeRoots(conservativeRoots);
565         visitProtectedObjects(heapRootVisitor);
566         visitArgumentBuffers(heapRootVisitor);
567         visitException(heapRootVisitor);
568         visitStrongHandles(heapRootVisitor);
569         visitHandleStack(heapRootVisitor);
570         traceCodeBlocksAndJITStubRoutines();
571         converge();
572     }
573
574     // Weak references must be marked last because their liveness depends on
575     // the liveness of the rest of the object graph.
576     visitWeakHandles(heapRootVisitor);
577
578     clearRememberedSet(rememberedSet);
579     m_sharedData.didFinishMarking();
580     updateObjectCounts(gcStartTime);
581     resetVisitors();
582 }
583
584 void Heap::copyBackingStores()
585 {
586     GCPHASE(CopyBackingStores);
587     if (m_operationInProgress == EdenCollection)
588         m_storageSpace.startedCopying<EdenCollection>();
589     else {
590         ASSERT(m_operationInProgress == FullCollection);
591         m_storageSpace.startedCopying<FullCollection>();
592     }
593
594     if (m_storageSpace.shouldDoCopyPhase()) {
595         m_sharedData.didStartCopying();
596         m_copyVisitor.startCopying();
597         m_copyVisitor.copyFromShared();
598         m_copyVisitor.doneCopying();
599         // We need to wait for everybody to finish and return their CopiedBlocks 
600         // before signaling that the phase is complete.
601         m_storageSpace.doneCopying();
602         m_sharedData.didFinishCopying();
603     } else
604         m_storageSpace.doneCopying();
605 }
606
607 void Heap::gatherStackRoots(ConservativeRoots& roots, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters)
608 {
609     GCPHASE(GatherStackRoots);
610     m_jitStubRoutines.clearMarks();
611     m_machineThreads.gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks, stackOrigin, stackTop, calleeSavedRegisters);
612 }
613
614 void Heap::gatherJSStackRoots(ConservativeRoots& roots)
615 {
616 #if !ENABLE(JIT)
617     GCPHASE(GatherJSStackRoots);
618     stack().gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks);
619 #else
620     UNUSED_PARAM(roots);
621 #endif
622 }
623
624 void Heap::gatherScratchBufferRoots(ConservativeRoots& roots)
625 {
626 #if ENABLE(DFG_JIT)
627     GCPHASE(GatherScratchBufferRoots);
628     m_vm->gatherConservativeRoots(roots);
629 #else
630     UNUSED_PARAM(roots);
631 #endif
632 }
633
634 void Heap::clearLivenessData()
635 {
636     GCPHASE(ClearLivenessData);
637     m_objectSpace.clearNewlyAllocated();
638     m_objectSpace.clearMarks();
639 }
640
641 void Heap::visitExternalRememberedSet()
642 {
643 #if JSC_OBJC_API_ENABLED
644     scanExternalRememberedSet(*m_vm, m_slotVisitor);
645 #endif
646 }
647
648 void Heap::visitSmallStrings()
649 {
650     GCPHASE(VisitSmallStrings);
651     if (!m_vm->smallStrings.needsToBeVisited(m_operationInProgress))
652         return;
653
654     m_vm->smallStrings.visitStrongReferences(m_slotVisitor);
655     if (Options::logGC() == GCLogging::Verbose)
656         dataLog("Small strings:\n", m_slotVisitor);
657     m_slotVisitor.donateAndDrain();
658 }
659
660 void Heap::visitConservativeRoots(ConservativeRoots& roots)
661 {
662     GCPHASE(VisitConservativeRoots);
663     m_slotVisitor.append(roots);
664
665     if (Options::logGC() == GCLogging::Verbose)
666         dataLog("Conservative Roots:\n", m_slotVisitor);
667
668     m_slotVisitor.donateAndDrain();
669 }
670
671 void Heap::visitCompilerWorklistWeakReferences()
672 {
673 #if ENABLE(DFG_JIT)
674     for (auto worklist : m_suspendedCompilerWorklists)
675         worklist->visitWeakReferences(m_slotVisitor, m_codeBlocks);
676
677     if (Options::logGC() == GCLogging::Verbose)
678         dataLog("DFG Worklists:\n", m_slotVisitor);
679 #endif
680 }
681
682 void Heap::removeDeadCompilerWorklistEntries()
683 {
684 #if ENABLE(DFG_JIT)
685     GCPHASE(FinalizeDFGWorklists);
686     for (auto worklist : m_suspendedCompilerWorklists)
687         worklist->removeDeadPlans(*m_vm);
688 #endif
689 }
690
691 void Heap::visitProtectedObjects(HeapRootVisitor& heapRootVisitor)
692 {
693     GCPHASE(VisitProtectedObjects);
694
695     for (auto& pair : m_protectedValues)
696         heapRootVisitor.visit(&pair.key);
697
698     if (Options::logGC() == GCLogging::Verbose)
699         dataLog("Protected Objects:\n", m_slotVisitor);
700
701     m_slotVisitor.donateAndDrain();
702 }
703
704 void Heap::visitArgumentBuffers(HeapRootVisitor& visitor)
705 {
706     GCPHASE(MarkingArgumentBuffers);
707     if (!m_markListSet || !m_markListSet->size())
708         return;
709
710     MarkedArgumentBuffer::markLists(visitor, *m_markListSet);
711
712     if (Options::logGC() == GCLogging::Verbose)
713         dataLog("Argument Buffers:\n", m_slotVisitor);
714
715     m_slotVisitor.donateAndDrain();
716 }
717
718 void Heap::visitException(HeapRootVisitor& visitor)
719 {
720     GCPHASE(MarkingException);
721     if (!m_vm->exception() && !m_vm->lastException())
722         return;
723
724     visitor.visit(m_vm->addressOfException());
725     visitor.visit(m_vm->addressOfLastException());
726
727     if (Options::logGC() == GCLogging::Verbose)
728         dataLog("Exceptions:\n", m_slotVisitor);
729
730     m_slotVisitor.donateAndDrain();
731 }
732
733 void Heap::visitStrongHandles(HeapRootVisitor& visitor)
734 {
735     GCPHASE(VisitStrongHandles);
736     m_handleSet.visitStrongHandles(visitor);
737
738     if (Options::logGC() == GCLogging::Verbose)
739         dataLog("Strong Handles:\n", m_slotVisitor);
740
741     m_slotVisitor.donateAndDrain();
742 }
743
744 void Heap::visitHandleStack(HeapRootVisitor& visitor)
745 {
746     GCPHASE(VisitHandleStack);
747     m_handleStack.visit(visitor);
748
749     if (Options::logGC() == GCLogging::Verbose)
750         dataLog("Handle Stack:\n", m_slotVisitor);
751
752     m_slotVisitor.donateAndDrain();
753 }
754
755 void Heap::traceCodeBlocksAndJITStubRoutines()
756 {
757     GCPHASE(TraceCodeBlocksAndJITStubRoutines);
758     m_codeBlocks.traceMarked(m_slotVisitor);
759     m_jitStubRoutines.traceMarkedStubRoutines(m_slotVisitor);
760
761     if (Options::logGC() == GCLogging::Verbose)
762         dataLog("Code Blocks and JIT Stub Routines:\n", m_slotVisitor);
763
764     m_slotVisitor.donateAndDrain();
765 }
766
767 void Heap::converge()
768 {
769 #if ENABLE(PARALLEL_GC)
770     GCPHASE(Convergence);
771     m_slotVisitor.drainFromShared(SlotVisitor::MasterDrain);
772 #endif
773 }
774
775 void Heap::visitWeakHandles(HeapRootVisitor& visitor)
776 {
777     GCPHASE(VisitingLiveWeakHandles);
778     while (true) {
779         m_objectSpace.visitWeakSets(visitor);
780         harvestWeakReferences();
781         visitCompilerWorklistWeakReferences();
782         m_codeBlocks.traceMarked(m_slotVisitor); // New "executing" code blocks may be discovered.
783         if (m_slotVisitor.isEmpty())
784             break;
785
786         if (Options::logGC() == GCLogging::Verbose)
787             dataLog("Live Weak Handles:\n", m_slotVisitor);
788
789         {
790             ParallelModeEnabler enabler(m_slotVisitor);
791             m_slotVisitor.donateAndDrain();
792 #if ENABLE(PARALLEL_GC)
793             m_slotVisitor.drainFromShared(SlotVisitor::MasterDrain);
794 #endif
795         }
796     }
797 }
798
799 void Heap::clearRememberedSet(Vector<const JSCell*>& rememberedSet)
800 {
801 #if ENABLE(GGC)
802     GCPHASE(ClearRememberedSet);
803     for (auto* cell : rememberedSet)
804         const_cast<JSCell*>(cell)->setRemembered(false);
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 JavaScript code, since
908     // we'll end up returning to deleted code.
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)->clearCode();
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)->clearUnlinkedCodeForRecompilation();
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     const_cast<JSCell*>(cell)->setRemembered(true);
979     m_slotVisitor.unconditionallyAppend(const_cast<JSCell*>(cell));
980 }
981
982 void Heap::collectAndSweep(HeapOperation collectionType)
983 {
984     if (!m_isSafeToCollect)
985         return;
986
987     collect(collectionType);
988
989     SamplingRegion samplingRegion("Garbage Collection: Sweeping");
990
991     DeferGCForAWhile deferGC(*this);
992     m_objectSpace.sweep();
993     m_objectSpace.shrink();
994
995     sweepAllLogicallyEmptyWeakBlocks();
996 }
997
998 static double minute = 60.0;
999
1000 NEVER_INLINE void Heap::collect(HeapOperation collectionType)
1001 {
1002     void* stackTop;
1003     ALLOCATE_AND_GET_REGISTER_STATE(registers);
1004
1005     collectImpl(collectionType, wtfThreadData().stack().origin(), &stackTop, registers);
1006
1007     sanitizeStackForVM(m_vm);
1008 }
1009
1010 NEVER_INLINE void Heap::collectImpl(HeapOperation collectionType, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters)
1011 {
1012 #if ENABLE(ALLOCATION_LOGGING)
1013     dataLogF("JSC GC starting collection.\n");
1014 #endif
1015     
1016     double before = 0;
1017     if (Options::logGC()) {
1018         dataLog("[GC: ");
1019         before = currentTimeMS();
1020     }
1021     
1022     SamplingRegion samplingRegion("Garbage Collection");
1023     
1024     if (vm()->typeProfiler()) {
1025         DeferGCForAWhile awhile(*this);
1026         vm()->typeProfilerLog()->processLogEntries(ASCIILiteral("GC"));
1027     }
1028     
1029     RELEASE_ASSERT(!m_deferralDepth);
1030     ASSERT(vm()->currentThreadIsHoldingAPILock());
1031     RELEASE_ASSERT(vm()->atomicStringTable() == wtfThreadData().atomicStringTable());
1032     ASSERT(m_isSafeToCollect);
1033     JAVASCRIPTCORE_GC_BEGIN();
1034     RELEASE_ASSERT(m_operationInProgress == NoOperation);
1035
1036     suspendCompilerThreads();
1037     willStartCollection(collectionType);
1038     GCPHASE(Collect);
1039
1040     double gcStartTime = WTF::monotonicallyIncreasingTime();
1041     if (m_verifier) {
1042         // Verify that live objects from the last GC cycle haven't been corrupted by
1043         // mutators before we begin this new GC cycle.
1044         m_verifier->verify(HeapVerifier::Phase::BeforeGC);
1045
1046         m_verifier->initializeGCCycle();
1047         m_verifier->gatherLiveObjects(HeapVerifier::Phase::BeforeMarking);
1048     }
1049
1050     deleteOldCode(gcStartTime);
1051     flushOldStructureIDTables();
1052     stopAllocation();
1053     flushWriteBarrierBuffer();
1054
1055     markRoots(gcStartTime, stackOrigin, stackTop, calleeSavedRegisters);
1056
1057     if (m_verifier) {
1058         m_verifier->gatherLiveObjects(HeapVerifier::Phase::AfterMarking);
1059         m_verifier->verify(HeapVerifier::Phase::AfterMarking);
1060     }
1061     JAVASCRIPTCORE_GC_MARKED();
1062
1063     if (vm()->typeProfiler())
1064         vm()->typeProfiler()->invalidateTypeSetCache();
1065
1066     reapWeakHandles();
1067     pruneStaleEntriesFromWeakGCMaps();
1068     sweepArrayBuffers();
1069     snapshotMarkedSpace();
1070
1071     copyBackingStores();
1072
1073     finalizeUnconditionalFinalizers();
1074     removeDeadCompilerWorklistEntries();
1075     deleteUnmarkedCompiledCode();
1076     deleteSourceProviderCaches();
1077     notifyIncrementalSweeper();
1078     rememberCurrentlyExecutingCodeBlocks();
1079
1080     resetAllocators();
1081     updateAllocationLimits();
1082     didFinishCollection(gcStartTime);
1083     resumeCompilerThreads();
1084
1085     if (m_verifier) {
1086         m_verifier->trimDeadObjects();
1087         m_verifier->verify(HeapVerifier::Phase::AfterGC);
1088     }
1089
1090     if (Options::logGC()) {
1091         double after = currentTimeMS();
1092         dataLog(after - before, " ms]\n");
1093     }
1094 }
1095
1096 void Heap::suspendCompilerThreads()
1097 {
1098 #if ENABLE(DFG_JIT)
1099     GCPHASE(SuspendCompilerThreads);
1100     ASSERT(m_suspendedCompilerWorklists.isEmpty());
1101     for (unsigned i = DFG::numberOfWorklists(); i--;) {
1102         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
1103             m_suspendedCompilerWorklists.append(worklist);
1104             worklist->suspendAllThreads();
1105         }
1106     }
1107 #endif
1108 }
1109
1110 void Heap::willStartCollection(HeapOperation collectionType)
1111 {
1112     GCPHASE(StartingCollection);
1113     if (shouldDoFullCollection(collectionType)) {
1114         m_operationInProgress = FullCollection;
1115         m_slotVisitor.clearMarkStack();
1116         m_shouldDoFullCollection = false;
1117         if (Options::logGC())
1118             dataLog("FullCollection, ");
1119     } else {
1120         m_operationInProgress = EdenCollection;
1121         if (Options::logGC())
1122             dataLog("EdenCollection, ");
1123     }
1124     if (m_operationInProgress == FullCollection) {
1125         m_sizeBeforeLastFullCollect = m_sizeAfterLastCollect + m_bytesAllocatedThisCycle;
1126         m_extraMemorySize = 0;
1127         m_deprecatedExtraMemorySize = 0;
1128
1129         if (m_fullActivityCallback)
1130             m_fullActivityCallback->willCollect();
1131     } else {
1132         ASSERT(m_operationInProgress == EdenCollection);
1133         m_sizeBeforeLastEdenCollect = m_sizeAfterLastCollect + m_bytesAllocatedThisCycle;
1134     }
1135
1136     if (m_edenActivityCallback)
1137         m_edenActivityCallback->willCollect();
1138 }
1139
1140 void Heap::deleteOldCode(double gcStartTime)
1141 {
1142     if (m_operationInProgress == EdenCollection)
1143         return;
1144
1145     GCPHASE(DeleteOldCode);
1146     if (gcStartTime - m_lastCodeDiscardTime > minute) {
1147         m_vm->regExpCache()->deleteAllCode();
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 void Heap::collectAllGarbageIfNotDoneRecently()
1415 {
1416     if (!m_fullActivityCallback) {
1417         collectAllGarbage();
1418         return;
1419     }
1420
1421     if (m_fullActivityCallback->didSyncGCRecently()) {
1422         // A synchronous GC was already requested recently so we merely accelerate next collection.
1423         reportAbandonedObjectGraph();
1424         return;
1425     }
1426
1427     m_fullActivityCallback->setDidSyncGCRecently();
1428     collectAllGarbage();
1429 }
1430
1431 class Zombify : public MarkedBlock::VoidFunctor {
1432 public:
1433     inline void visit(JSCell* cell)
1434     {
1435         void** current = reinterpret_cast<void**>(cell);
1436
1437         // We want to maintain zapped-ness because that's how we know if we've called 
1438         // the destructor.
1439         if (cell->isZapped())
1440             current++;
1441
1442         void* limit = static_cast<void*>(reinterpret_cast<char*>(cell) + MarkedBlock::blockFor(cell)->cellSize());
1443         for (; current < limit; current++)
1444             *current = zombifiedBits;
1445     }
1446     IterationStatus operator()(JSCell* cell)
1447     {
1448         visit(cell);
1449         return IterationStatus::Continue;
1450     }
1451 };
1452
1453 void Heap::zombifyDeadObjects()
1454 {
1455     // Sweep now because destructors will crash once we're zombified.
1456     {
1457         SamplingRegion samplingRegion("Garbage Collection: Sweeping");
1458         m_objectSpace.zombifySweep();
1459     }
1460     HeapIterationScope iterationScope(*this);
1461     m_objectSpace.forEachDeadCell<Zombify>(iterationScope);
1462 }
1463
1464 void Heap::flushWriteBarrierBuffer(JSCell* cell)
1465 {
1466 #if ENABLE(GGC)
1467     m_writeBarrierBuffer.flush(*this);
1468     m_writeBarrierBuffer.add(cell);
1469 #else
1470     UNUSED_PARAM(cell);
1471 #endif
1472 }
1473
1474 bool Heap::shouldDoFullCollection(HeapOperation requestedCollectionType) const
1475 {
1476 #if ENABLE(GGC)
1477     if (Options::alwaysDoFullCollection())
1478         return true;
1479
1480     switch (requestedCollectionType) {
1481     case EdenCollection:
1482         return false;
1483     case FullCollection:
1484         return true;
1485     case AnyCollection:
1486         return m_shouldDoFullCollection;
1487     default:
1488         RELEASE_ASSERT_NOT_REACHED();
1489         return false;
1490     }
1491     RELEASE_ASSERT_NOT_REACHED();
1492     return false;
1493 #else
1494     UNUSED_PARAM(requestedCollectionType);
1495     return true;
1496 #endif
1497 }
1498
1499 void Heap::addLogicallyEmptyWeakBlock(WeakBlock* block)
1500 {
1501     m_logicallyEmptyWeakBlocks.append(block);
1502 }
1503
1504 void Heap::sweepAllLogicallyEmptyWeakBlocks()
1505 {
1506     if (m_logicallyEmptyWeakBlocks.isEmpty())
1507         return;
1508
1509     m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0;
1510     while (sweepNextLogicallyEmptyWeakBlock()) { }
1511 }
1512
1513 bool Heap::sweepNextLogicallyEmptyWeakBlock()
1514 {
1515     if (m_indexOfNextLogicallyEmptyWeakBlockToSweep == WTF::notFound)
1516         return false;
1517
1518     WeakBlock* block = m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep];
1519
1520     block->sweep();
1521     if (block->isEmpty()) {
1522         std::swap(m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep], m_logicallyEmptyWeakBlocks.last());
1523         m_logicallyEmptyWeakBlocks.removeLast();
1524         WeakBlock::destroy(block);
1525     } else
1526         m_indexOfNextLogicallyEmptyWeakBlockToSweep++;
1527
1528     if (m_indexOfNextLogicallyEmptyWeakBlockToSweep >= m_logicallyEmptyWeakBlocks.size()) {
1529         m_indexOfNextLogicallyEmptyWeakBlockToSweep = WTF::notFound;
1530         return false;
1531     }
1532
1533     return true;
1534 }
1535
1536 } // namespace JSC