[JSC] Weak should only accept cell pointees.
[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::markRoots(double gcStartTime, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters)
514 {
515     SamplingRegion samplingRegion("Garbage Collection: Marking");
516
517     GCPHASE(MarkRoots);
518     ASSERT(isValidThreadState(m_vm));
519
520 #if ENABLE(GGC)
521     Vector<const JSCell*> rememberedSet(m_slotVisitor.markStack().size());
522     m_slotVisitor.markStack().fillVector(rememberedSet);
523 #else
524     Vector<const JSCell*> rememberedSet;
525 #endif
526
527 #if ENABLE(DFG_JIT)
528     DFG::clearCodeBlockMarks(*m_vm);
529 #endif
530     if (m_operationInProgress == EdenCollection)
531         m_codeBlocks.clearMarksForEdenCollection(rememberedSet);
532     else
533         m_codeBlocks.clearMarksForFullCollection();
534
535     // We gather conservative roots before clearing mark bits because conservative
536     // gathering uses the mark bits to determine whether a reference is valid.
537     ConservativeRoots conservativeRoots(&m_objectSpace.blocks(), &m_storageSpace);
538     gatherStackRoots(conservativeRoots, stackOrigin, stackTop, calleeSavedRegisters);
539     gatherJSStackRoots(conservativeRoots);
540     gatherScratchBufferRoots(conservativeRoots);
541
542     clearLivenessData();
543
544     m_sharedData.didStartMarking();
545     m_slotVisitor.didStartMarking();
546     HeapRootVisitor heapRootVisitor(m_slotVisitor);
547
548     {
549         ParallelModeEnabler enabler(m_slotVisitor);
550
551         visitExternalRememberedSet();
552         visitSmallStrings();
553         visitConservativeRoots(conservativeRoots);
554         visitProtectedObjects(heapRootVisitor);
555         visitArgumentBuffers(heapRootVisitor);
556         visitException(heapRootVisitor);
557         visitStrongHandles(heapRootVisitor);
558         visitHandleStack(heapRootVisitor);
559         traceCodeBlocksAndJITStubRoutines();
560         converge();
561     }
562
563     // Weak references must be marked last because their liveness depends on
564     // the liveness of the rest of the object graph.
565     visitWeakHandles(heapRootVisitor);
566
567     clearRememberedSet(rememberedSet);
568     m_sharedData.didFinishMarking();
569     updateObjectCounts(gcStartTime);
570     resetVisitors();
571 }
572
573 void Heap::copyBackingStores()
574 {
575     GCPHASE(CopyBackingStores);
576     if (m_operationInProgress == EdenCollection)
577         m_storageSpace.startedCopying<EdenCollection>();
578     else {
579         ASSERT(m_operationInProgress == FullCollection);
580         m_storageSpace.startedCopying<FullCollection>();
581     }
582
583     if (m_storageSpace.shouldDoCopyPhase()) {
584         m_sharedData.didStartCopying();
585         m_copyVisitor.startCopying();
586         m_copyVisitor.copyFromShared();
587         m_copyVisitor.doneCopying();
588         // We need to wait for everybody to finish and return their CopiedBlocks 
589         // before signaling that the phase is complete.
590         m_storageSpace.doneCopying();
591         m_sharedData.didFinishCopying();
592     } else
593         m_storageSpace.doneCopying();
594 }
595
596 void Heap::gatherStackRoots(ConservativeRoots& roots, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters)
597 {
598     GCPHASE(GatherStackRoots);
599     m_jitStubRoutines.clearMarks();
600     m_machineThreads.gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks, stackOrigin, stackTop, calleeSavedRegisters);
601 }
602
603 void Heap::gatherJSStackRoots(ConservativeRoots& roots)
604 {
605 #if !ENABLE(JIT)
606     GCPHASE(GatherJSStackRoots);
607     stack().gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks);
608 #else
609     UNUSED_PARAM(roots);
610 #endif
611 }
612
613 void Heap::gatherScratchBufferRoots(ConservativeRoots& roots)
614 {
615 #if ENABLE(DFG_JIT)
616     GCPHASE(GatherScratchBufferRoots);
617     m_vm->gatherConservativeRoots(roots);
618 #else
619     UNUSED_PARAM(roots);
620 #endif
621 }
622
623 void Heap::clearLivenessData()
624 {
625     GCPHASE(ClearLivenessData);
626     m_objectSpace.clearNewlyAllocated();
627     m_objectSpace.clearMarks();
628 }
629
630 void Heap::visitExternalRememberedSet()
631 {
632 #if JSC_OBJC_API_ENABLED
633     scanExternalRememberedSet(*m_vm, m_slotVisitor);
634 #endif
635 }
636
637 void Heap::visitSmallStrings()
638 {
639     GCPHASE(VisitSmallStrings);
640     if (!m_vm->smallStrings.needsToBeVisited(m_operationInProgress))
641         return;
642
643     m_vm->smallStrings.visitStrongReferences(m_slotVisitor);
644     if (Options::logGC() == GCLogging::Verbose)
645         dataLog("Small strings:\n", m_slotVisitor);
646     m_slotVisitor.donateAndDrain();
647 }
648
649 void Heap::visitConservativeRoots(ConservativeRoots& roots)
650 {
651     GCPHASE(VisitConservativeRoots);
652     m_slotVisitor.append(roots);
653
654     if (Options::logGC() == GCLogging::Verbose)
655         dataLog("Conservative Roots:\n", m_slotVisitor);
656
657     m_slotVisitor.donateAndDrain();
658 }
659
660 void Heap::visitCompilerWorklistWeakReferences()
661 {
662 #if ENABLE(DFG_JIT)
663     for (auto worklist : m_suspendedCompilerWorklists)
664         worklist->visitWeakReferences(m_slotVisitor);
665
666     if (Options::logGC() == GCLogging::Verbose)
667         dataLog("DFG Worklists:\n", m_slotVisitor);
668 #endif
669 }
670
671 void Heap::removeDeadCompilerWorklistEntries()
672 {
673 #if ENABLE(DFG_JIT)
674     GCPHASE(FinalizeDFGWorklists);
675     for (auto worklist : m_suspendedCompilerWorklists)
676         worklist->removeDeadPlans(*m_vm);
677 #endif
678 }
679
680 void Heap::visitProtectedObjects(HeapRootVisitor& heapRootVisitor)
681 {
682     GCPHASE(VisitProtectedObjects);
683
684     for (auto& pair : m_protectedValues)
685         heapRootVisitor.visit(&pair.key);
686
687     if (Options::logGC() == GCLogging::Verbose)
688         dataLog("Protected Objects:\n", m_slotVisitor);
689
690     m_slotVisitor.donateAndDrain();
691 }
692
693 void Heap::visitArgumentBuffers(HeapRootVisitor& visitor)
694 {
695     GCPHASE(MarkingArgumentBuffers);
696     if (!m_markListSet || !m_markListSet->size())
697         return;
698
699     MarkedArgumentBuffer::markLists(visitor, *m_markListSet);
700
701     if (Options::logGC() == GCLogging::Verbose)
702         dataLog("Argument Buffers:\n", m_slotVisitor);
703
704     m_slotVisitor.donateAndDrain();
705 }
706
707 void Heap::visitException(HeapRootVisitor& visitor)
708 {
709     GCPHASE(MarkingException);
710     if (!m_vm->exception() && !m_vm->lastException())
711         return;
712
713     visitor.visit(m_vm->addressOfException());
714     visitor.visit(m_vm->addressOfLastException());
715
716     if (Options::logGC() == GCLogging::Verbose)
717         dataLog("Exceptions:\n", m_slotVisitor);
718
719     m_slotVisitor.donateAndDrain();
720 }
721
722 void Heap::visitStrongHandles(HeapRootVisitor& visitor)
723 {
724     GCPHASE(VisitStrongHandles);
725     m_handleSet.visitStrongHandles(visitor);
726
727     if (Options::logGC() == GCLogging::Verbose)
728         dataLog("Strong Handles:\n", m_slotVisitor);
729
730     m_slotVisitor.donateAndDrain();
731 }
732
733 void Heap::visitHandleStack(HeapRootVisitor& visitor)
734 {
735     GCPHASE(VisitHandleStack);
736     m_handleStack.visit(visitor);
737
738     if (Options::logGC() == GCLogging::Verbose)
739         dataLog("Handle Stack:\n", m_slotVisitor);
740
741     m_slotVisitor.donateAndDrain();
742 }
743
744 void Heap::traceCodeBlocksAndJITStubRoutines()
745 {
746     GCPHASE(TraceCodeBlocksAndJITStubRoutines);
747     m_codeBlocks.traceMarked(m_slotVisitor);
748     m_jitStubRoutines.traceMarkedStubRoutines(m_slotVisitor);
749
750     if (Options::logGC() == GCLogging::Verbose)
751         dataLog("Code Blocks and JIT Stub Routines:\n", m_slotVisitor);
752
753     m_slotVisitor.donateAndDrain();
754 }
755
756 void Heap::converge()
757 {
758 #if ENABLE(PARALLEL_GC)
759     GCPHASE(Convergence);
760     m_slotVisitor.drainFromShared(SlotVisitor::MasterDrain);
761 #endif
762 }
763
764 void Heap::visitWeakHandles(HeapRootVisitor& visitor)
765 {
766     GCPHASE(VisitingLiveWeakHandles);
767     while (true) {
768         m_objectSpace.visitWeakSets(visitor);
769         harvestWeakReferences();
770         visitCompilerWorklistWeakReferences();
771         if (m_slotVisitor.isEmpty())
772             break;
773
774         if (Options::logGC() == GCLogging::Verbose)
775             dataLog("Live Weak Handles:\n", m_slotVisitor);
776
777         {
778             ParallelModeEnabler enabler(m_slotVisitor);
779             m_slotVisitor.donateAndDrain();
780 #if ENABLE(PARALLEL_GC)
781             m_slotVisitor.drainFromShared(SlotVisitor::MasterDrain);
782 #endif
783         }
784     }
785 }
786
787 void Heap::clearRememberedSet(Vector<const JSCell*>& rememberedSet)
788 {
789 #if ENABLE(GGC)
790     GCPHASE(ClearRememberedSet);
791     for (auto* cell : rememberedSet)
792         const_cast<JSCell*>(cell)->setRemembered(false);
793 #else
794     UNUSED_PARAM(rememberedSet);
795 #endif
796 }
797
798 void Heap::updateObjectCounts(double gcStartTime)
799 {
800     GCCOUNTER(VisitedValueCount, m_slotVisitor.visitCount());
801
802     if (Options::logGC() == GCLogging::Verbose) {
803         size_t visitCount = m_slotVisitor.visitCount();
804 #if ENABLE(PARALLEL_GC)
805         visitCount += m_sharedData.childVisitCount();
806 #endif
807         dataLogF("\nNumber of live Objects after GC %lu, took %.6f secs\n", static_cast<unsigned long>(visitCount), WTF::monotonicallyIncreasingTime() - gcStartTime);
808     }
809     
810     size_t bytesRemovedFromOldSpaceDueToReallocation =
811         m_storageSpace.takeBytesRemovedFromOldSpaceDueToReallocation();
812     
813     if (m_operationInProgress == FullCollection) {
814         m_totalBytesVisited = 0;
815         m_totalBytesCopied = 0;
816     } else
817         m_totalBytesCopied -= bytesRemovedFromOldSpaceDueToReallocation;
818     
819     m_totalBytesVisited += m_slotVisitor.bytesVisited();
820     m_totalBytesCopied += m_slotVisitor.bytesCopied();
821 #if ENABLE(PARALLEL_GC)
822     m_totalBytesVisited += m_sharedData.childBytesVisited();
823     m_totalBytesCopied += m_sharedData.childBytesCopied();
824 #endif
825 }
826
827 void Heap::resetVisitors()
828 {
829     m_slotVisitor.reset();
830 #if ENABLE(PARALLEL_GC)
831     m_sharedData.resetChildren();
832 #endif
833     m_sharedData.reset();
834 }
835
836 size_t Heap::objectCount()
837 {
838     return m_objectSpace.objectCount();
839 }
840
841 size_t Heap::extraMemorySize()
842 {
843     return m_extraMemorySize + m_deprecatedExtraMemorySize + m_arrayBuffers.size();
844 }
845
846 size_t Heap::size()
847 {
848     return m_objectSpace.size() + m_storageSpace.size() + extraMemorySize();
849 }
850
851 size_t Heap::capacity()
852 {
853     return m_objectSpace.capacity() + m_storageSpace.capacity() + extraMemorySize();
854 }
855
856 size_t Heap::sizeAfterCollect()
857 {
858     // The result here may not agree with the normal Heap::size(). 
859     // This is due to the fact that we only count live copied bytes
860     // rather than all used (including dead) copied bytes, thus it's 
861     // always the case that m_totalBytesCopied <= m_storageSpace.size(). 
862     ASSERT(m_totalBytesCopied <= m_storageSpace.size());
863     return m_totalBytesVisited + m_totalBytesCopied + extraMemorySize();
864 }
865
866 size_t Heap::protectedGlobalObjectCount()
867 {
868     return forEachProtectedCell<CountIfGlobalObject>();
869 }
870
871 size_t Heap::globalObjectCount()
872 {
873     HeapIterationScope iterationScope(*this);
874     return m_objectSpace.forEachLiveCell<CountIfGlobalObject>(iterationScope);
875 }
876
877 size_t Heap::protectedObjectCount()
878 {
879     return forEachProtectedCell<Count>();
880 }
881
882 std::unique_ptr<TypeCountSet> Heap::protectedObjectTypeCounts()
883 {
884     return forEachProtectedCell<RecordType>();
885 }
886
887 std::unique_ptr<TypeCountSet> Heap::objectTypeCounts()
888 {
889     HeapIterationScope iterationScope(*this);
890     return m_objectSpace.forEachLiveCell<RecordType>(iterationScope);
891 }
892
893 void Heap::deleteAllCodeBlocks()
894 {
895     // If JavaScript is running, it's not safe to delete JavaScript code, since
896     // we'll end up returning to deleted code.
897     if (m_vm->entryScope)
898         return;
899     
900     // If we have things on any worklist, then don't delete code. This is kind of
901     // a weird heuristic. It's definitely not safe to throw away code that is on
902     // the worklist. But this change was made in a hurry so we just avoid throwing
903     // away any code if there is any code on any worklist. I suspect that this
904     // might not actually be too dumb: if there is code on worklists then that
905     // means that we are running some hot JS code right now. Maybe causing
906     // recompilations isn't a good idea.
907 #if ENABLE(DFG_JIT)
908     for (unsigned i = DFG::numberOfWorklists(); i--;) {
909         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
910             if (worklist->isActiveForVM(*vm()))
911                 return;
912         }
913     }
914 #endif // ENABLE(DFG_JIT)
915
916     for (ExecutableBase* current : m_executables) {
917         if (!current->isFunctionExecutable())
918             continue;
919         static_cast<FunctionExecutable*>(current)->clearCode();
920     }
921
922     ASSERT(m_operationInProgress == FullCollection || m_operationInProgress == NoOperation);
923     m_codeBlocks.clearMarksForFullCollection();
924     m_codeBlocks.deleteUnmarkedAndUnreferenced(FullCollection);
925 }
926
927 void Heap::deleteAllUnlinkedCodeBlocks()
928 {
929     for (ExecutableBase* current : m_executables) {
930         if (!current->isFunctionExecutable())
931             continue;
932         static_cast<FunctionExecutable*>(current)->unlinkedExecutable()->clearCode();
933     }
934 }
935
936 void Heap::clearUnmarkedExecutables()
937 {
938     GCPHASE(ClearUnmarkedExecutables);
939     for (unsigned i = m_executables.size(); i--;) {
940         ExecutableBase* current = m_executables[i];
941         if (isMarked(current))
942             continue;
943
944         // We do this because executable memory is limited on some platforms and because
945         // CodeBlock requires eager finalization.
946         ExecutableBase::clearCodeVirtual(current);
947         std::swap(m_executables[i], m_executables.last());
948         m_executables.removeLast();
949     }
950 }
951
952 void Heap::deleteUnmarkedCompiledCode()
953 {
954     GCPHASE(DeleteCodeBlocks);
955     clearUnmarkedExecutables();
956     m_codeBlocks.deleteUnmarkedAndUnreferenced(m_operationInProgress);
957     m_jitStubRoutines.deleteUnmarkedJettisonedStubRoutines();
958 }
959
960 void Heap::addToRememberedSet(const JSCell* cell)
961 {
962     ASSERT(cell);
963     ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread());
964     if (isRemembered(cell))
965         return;
966     const_cast<JSCell*>(cell)->setRemembered(true);
967     m_slotVisitor.unconditionallyAppend(const_cast<JSCell*>(cell));
968 }
969
970 void Heap::collectAndSweep(HeapOperation collectionType)
971 {
972     if (!m_isSafeToCollect)
973         return;
974
975     collect(collectionType);
976
977     SamplingRegion samplingRegion("Garbage Collection: Sweeping");
978
979     DeferGCForAWhile deferGC(*this);
980     m_objectSpace.sweep();
981     m_objectSpace.shrink();
982
983     sweepAllLogicallyEmptyWeakBlocks();
984 }
985
986 static double minute = 60.0;
987
988 NEVER_INLINE void Heap::collect(HeapOperation collectionType)
989 {
990     void* stackTop;
991     ALLOCATE_AND_GET_REGISTER_STATE(registers);
992
993     collectImpl(collectionType, wtfThreadData().stack().origin(), &stackTop, registers);
994
995     sanitizeStackForVM(m_vm);
996 }
997
998 NEVER_INLINE void Heap::collectImpl(HeapOperation collectionType, void* stackOrigin, void* stackTop, MachineThreads::RegisterState& calleeSavedRegisters)
999 {
1000 #if ENABLE(ALLOCATION_LOGGING)
1001     dataLogF("JSC GC starting collection.\n");
1002 #endif
1003     
1004     double before = 0;
1005     if (Options::logGC()) {
1006         dataLog("[GC: ");
1007         before = currentTimeMS();
1008     }
1009     
1010     SamplingRegion samplingRegion("Garbage Collection");
1011     
1012     if (vm()->typeProfiler()) {
1013         DeferGCForAWhile awhile(*this);
1014         vm()->typeProfilerLog()->processLogEntries(ASCIILiteral("GC"));
1015     }
1016     
1017     RELEASE_ASSERT(!m_deferralDepth);
1018     ASSERT(vm()->currentThreadIsHoldingAPILock());
1019     RELEASE_ASSERT(vm()->atomicStringTable() == wtfThreadData().atomicStringTable());
1020     ASSERT(m_isSafeToCollect);
1021     JAVASCRIPTCORE_GC_BEGIN();
1022     RELEASE_ASSERT(m_operationInProgress == NoOperation);
1023
1024     suspendCompilerThreads();
1025     willStartCollection(collectionType);
1026     GCPHASE(Collect);
1027
1028     double gcStartTime = WTF::monotonicallyIncreasingTime();
1029     if (m_verifier) {
1030         // Verify that live objects from the last GC cycle haven't been corrupted by
1031         // mutators before we begin this new GC cycle.
1032         m_verifier->verify(HeapVerifier::Phase::BeforeGC);
1033
1034         m_verifier->initializeGCCycle();
1035         m_verifier->gatherLiveObjects(HeapVerifier::Phase::BeforeMarking);
1036     }
1037
1038     deleteOldCode(gcStartTime);
1039     flushOldStructureIDTables();
1040     stopAllocation();
1041     flushWriteBarrierBuffer();
1042
1043     markRoots(gcStartTime, stackOrigin, stackTop, calleeSavedRegisters);
1044
1045     if (m_verifier) {
1046         m_verifier->gatherLiveObjects(HeapVerifier::Phase::AfterMarking);
1047         m_verifier->verify(HeapVerifier::Phase::AfterMarking);
1048     }
1049     JAVASCRIPTCORE_GC_MARKED();
1050
1051     if (vm()->typeProfiler())
1052         vm()->typeProfiler()->invalidateTypeSetCache();
1053
1054     reapWeakHandles();
1055     pruneStaleEntriesFromWeakGCMaps();
1056     sweepArrayBuffers();
1057     snapshotMarkedSpace();
1058
1059     copyBackingStores();
1060
1061     finalizeUnconditionalFinalizers();
1062     removeDeadCompilerWorklistEntries();
1063     deleteUnmarkedCompiledCode();
1064     deleteSourceProviderCaches();
1065     notifyIncrementalSweeper();
1066     rememberCurrentlyExecutingCodeBlocks();
1067
1068     resetAllocators();
1069     updateAllocationLimits();
1070     didFinishCollection(gcStartTime);
1071     resumeCompilerThreads();
1072
1073     if (m_verifier) {
1074         m_verifier->trimDeadObjects();
1075         m_verifier->verify(HeapVerifier::Phase::AfterGC);
1076     }
1077
1078     if (Options::logGC()) {
1079         double after = currentTimeMS();
1080         dataLog(after - before, " ms]\n");
1081     }
1082 }
1083
1084 void Heap::suspendCompilerThreads()
1085 {
1086 #if ENABLE(DFG_JIT)
1087     GCPHASE(SuspendCompilerThreads);
1088     ASSERT(m_suspendedCompilerWorklists.isEmpty());
1089     for (unsigned i = DFG::numberOfWorklists(); i--;) {
1090         if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
1091             m_suspendedCompilerWorklists.append(worklist);
1092             worklist->suspendAllThreads();
1093         }
1094     }
1095 #endif
1096 }
1097
1098 void Heap::willStartCollection(HeapOperation collectionType)
1099 {
1100     GCPHASE(StartingCollection);
1101     if (shouldDoFullCollection(collectionType)) {
1102         m_operationInProgress = FullCollection;
1103         m_slotVisitor.clearMarkStack();
1104         m_shouldDoFullCollection = false;
1105         if (Options::logGC())
1106             dataLog("FullCollection, ");
1107     } else {
1108         m_operationInProgress = EdenCollection;
1109         if (Options::logGC())
1110             dataLog("EdenCollection, ");
1111     }
1112     if (m_operationInProgress == FullCollection) {
1113         m_sizeBeforeLastFullCollect = m_sizeAfterLastCollect + m_bytesAllocatedThisCycle;
1114         m_extraMemorySize = 0;
1115         m_deprecatedExtraMemorySize = 0;
1116
1117         if (m_fullActivityCallback)
1118             m_fullActivityCallback->willCollect();
1119     } else {
1120         ASSERT(m_operationInProgress == EdenCollection);
1121         m_sizeBeforeLastEdenCollect = m_sizeAfterLastCollect + m_bytesAllocatedThisCycle;
1122     }
1123
1124     if (m_edenActivityCallback)
1125         m_edenActivityCallback->willCollect();
1126 }
1127
1128 void Heap::deleteOldCode(double gcStartTime)
1129 {
1130     if (m_operationInProgress == EdenCollection)
1131         return;
1132
1133     GCPHASE(DeleteOldCode);
1134     if (gcStartTime - m_lastCodeDiscardTime > minute) {
1135         m_vm->regExpCache()->deleteAllCode();
1136         deleteAllCodeBlocks();
1137         m_lastCodeDiscardTime = WTF::monotonicallyIncreasingTime();
1138     }
1139 }
1140
1141 void Heap::flushOldStructureIDTables()
1142 {
1143     GCPHASE(FlushOldStructureIDTables);
1144     m_structureIDTable.flushOldTables();
1145 }
1146
1147 void Heap::flushWriteBarrierBuffer()
1148 {
1149     GCPHASE(FlushWriteBarrierBuffer);
1150     if (m_operationInProgress == EdenCollection) {
1151         m_writeBarrierBuffer.flush(*this);
1152         return;
1153     }
1154     m_writeBarrierBuffer.reset();
1155 }
1156
1157 void Heap::stopAllocation()
1158 {
1159     GCPHASE(StopAllocation);
1160     m_objectSpace.stopAllocating();
1161     if (m_operationInProgress == FullCollection)
1162         m_storageSpace.didStartFullCollection();
1163 }
1164
1165 void Heap::reapWeakHandles()
1166 {
1167     GCPHASE(ReapingWeakHandles);
1168     m_objectSpace.reapWeakSets();
1169 }
1170
1171 void Heap::pruneStaleEntriesFromWeakGCMaps()
1172 {
1173     GCPHASE(PruningStaleEntriesFromWeakGCMaps);
1174     if (m_operationInProgress != FullCollection)
1175         return;
1176     for (auto& pruneCallback : m_weakGCMaps.values())
1177         pruneCallback();
1178 }
1179
1180 void Heap::sweepArrayBuffers()
1181 {
1182     GCPHASE(SweepingArrayBuffers);
1183     m_arrayBuffers.sweep();
1184 }
1185
1186 struct MarkedBlockSnapshotFunctor : public MarkedBlock::VoidFunctor {
1187     MarkedBlockSnapshotFunctor(Vector<MarkedBlock*>& blocks) 
1188         : m_index(0) 
1189         , m_blocks(blocks)
1190     {
1191     }
1192
1193     void operator()(MarkedBlock* block) { m_blocks[m_index++] = block; }
1194
1195     size_t m_index;
1196     Vector<MarkedBlock*>& m_blocks;
1197 };
1198
1199 void Heap::snapshotMarkedSpace()
1200 {
1201     GCPHASE(SnapshotMarkedSpace);
1202
1203     if (m_operationInProgress == EdenCollection) {
1204         m_blockSnapshot.appendVector(m_objectSpace.blocksWithNewObjects());
1205         // Sort and deduplicate the block snapshot since we might be appending to an unfinished work list.
1206         std::sort(m_blockSnapshot.begin(), m_blockSnapshot.end());
1207         m_blockSnapshot.shrink(std::unique(m_blockSnapshot.begin(), m_blockSnapshot.end()) - m_blockSnapshot.begin());
1208     } else {
1209         m_blockSnapshot.resizeToFit(m_objectSpace.blocks().set().size());
1210         MarkedBlockSnapshotFunctor functor(m_blockSnapshot);
1211         m_objectSpace.forEachBlock(functor);
1212     }
1213 }
1214
1215 void Heap::deleteSourceProviderCaches()
1216 {
1217     GCPHASE(DeleteSourceProviderCaches);
1218     m_vm->clearSourceProviderCaches();
1219 }
1220
1221 void Heap::notifyIncrementalSweeper()
1222 {
1223     GCPHASE(NotifyIncrementalSweeper);
1224
1225     if (m_operationInProgress == FullCollection) {
1226         if (!m_logicallyEmptyWeakBlocks.isEmpty())
1227             m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0;
1228     }
1229
1230     m_sweeper->startSweeping();
1231 }
1232
1233 void Heap::rememberCurrentlyExecutingCodeBlocks()
1234 {
1235     GCPHASE(RememberCurrentlyExecutingCodeBlocks);
1236     m_codeBlocks.rememberCurrentlyExecutingCodeBlocks(this);
1237 }
1238
1239 void Heap::resetAllocators()
1240 {
1241     GCPHASE(ResetAllocators);
1242     m_objectSpace.resetAllocators();
1243 }
1244
1245 void Heap::updateAllocationLimits()
1246 {
1247     GCPHASE(UpdateAllocationLimits);
1248     size_t currentHeapSize = sizeAfterCollect();
1249     if (Options::gcMaxHeapSize() && currentHeapSize > Options::gcMaxHeapSize())
1250         HeapStatistics::exitWithFailure();
1251
1252     if (m_operationInProgress == FullCollection) {
1253         // To avoid pathological GC churn in very small and very large heaps, we set
1254         // the new allocation limit based on the current size of the heap, with a
1255         // fixed minimum.
1256         m_maxHeapSize = max(minHeapSize(m_heapType, m_ramSize), proportionalHeapSize(currentHeapSize, m_ramSize));
1257         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
1258         m_sizeAfterLastFullCollect = currentHeapSize;
1259         m_bytesAbandonedSinceLastFullCollect = 0;
1260     } else {
1261         ASSERT(currentHeapSize >= m_sizeAfterLastCollect);
1262         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
1263         m_sizeAfterLastEdenCollect = currentHeapSize;
1264         double edenToOldGenerationRatio = (double)m_maxEdenSize / (double)m_maxHeapSize;
1265         double minEdenToOldGenerationRatio = 1.0 / 3.0;
1266         if (edenToOldGenerationRatio < minEdenToOldGenerationRatio)
1267             m_shouldDoFullCollection = true;
1268         m_maxHeapSize += currentHeapSize - m_sizeAfterLastCollect;
1269         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
1270         if (m_fullActivityCallback) {
1271             ASSERT(currentHeapSize >= m_sizeAfterLastFullCollect);
1272             m_fullActivityCallback->didAllocate(currentHeapSize - m_sizeAfterLastFullCollect);
1273         }
1274     }
1275
1276     m_sizeAfterLastCollect = currentHeapSize;
1277     m_bytesAllocatedThisCycle = 0;
1278
1279     if (Options::logGC())
1280         dataLog(currentHeapSize / 1024, " kb, ");
1281 }
1282
1283 void Heap::didFinishCollection(double gcStartTime)
1284 {
1285     GCPHASE(FinishingCollection);
1286     double gcEndTime = WTF::monotonicallyIncreasingTime();
1287     if (m_operationInProgress == FullCollection)
1288         m_lastFullGCLength = gcEndTime - gcStartTime;
1289     else
1290         m_lastEdenGCLength = gcEndTime - gcStartTime;
1291
1292     if (Options::recordGCPauseTimes())
1293         HeapStatistics::recordGCPauseTime(gcStartTime, gcEndTime);
1294
1295     if (Options::useZombieMode())
1296         zombifyDeadObjects();
1297
1298     if (Options::objectsAreImmortal())
1299         markDeadObjects();
1300
1301     if (Options::showObjectStatistics())
1302         HeapStatistics::showObjectStatistics(this);
1303
1304     if (Options::logGC() == GCLogging::Verbose)
1305         GCLogging::dumpObjectGraph(this);
1306
1307     RELEASE_ASSERT(m_operationInProgress == EdenCollection || m_operationInProgress == FullCollection);
1308     m_operationInProgress = NoOperation;
1309     JAVASCRIPTCORE_GC_END();
1310 }
1311
1312 void Heap::resumeCompilerThreads()
1313 {
1314 #if ENABLE(DFG_JIT)
1315     GCPHASE(ResumeCompilerThreads);
1316     for (auto worklist : m_suspendedCompilerWorklists)
1317         worklist->resumeAllThreads();
1318     m_suspendedCompilerWorklists.clear();
1319 #endif
1320 }
1321
1322 void Heap::markDeadObjects()
1323 {
1324     HeapIterationScope iterationScope(*this);
1325     m_objectSpace.forEachDeadCell<MarkObject>(iterationScope);
1326 }
1327
1328 void Heap::setFullActivityCallback(PassRefPtr<FullGCActivityCallback> activityCallback)
1329 {
1330     m_fullActivityCallback = activityCallback;
1331 }
1332
1333 void Heap::setEdenActivityCallback(PassRefPtr<EdenGCActivityCallback> activityCallback)
1334 {
1335     m_edenActivityCallback = activityCallback;
1336 }
1337
1338 GCActivityCallback* Heap::fullActivityCallback()
1339 {
1340     return m_fullActivityCallback.get();
1341 }
1342
1343 GCActivityCallback* Heap::edenActivityCallback()
1344 {
1345     return m_edenActivityCallback.get();
1346 }
1347
1348 void Heap::setIncrementalSweeper(std::unique_ptr<IncrementalSweeper> sweeper)
1349 {
1350     m_sweeper = WTF::move(sweeper);
1351 }
1352
1353 IncrementalSweeper* Heap::sweeper()
1354 {
1355     return m_sweeper.get();
1356 }
1357
1358 void Heap::setGarbageCollectionTimerEnabled(bool enable)
1359 {
1360     if (m_fullActivityCallback)
1361         m_fullActivityCallback->setEnabled(enable);
1362     if (m_edenActivityCallback)
1363         m_edenActivityCallback->setEnabled(enable);
1364 }
1365
1366 void Heap::didAllocate(size_t bytes)
1367 {
1368     if (m_edenActivityCallback)
1369         m_edenActivityCallback->didAllocate(m_bytesAllocatedThisCycle + m_bytesAbandonedSinceLastFullCollect);
1370     m_bytesAllocatedThisCycle += bytes;
1371 }
1372
1373 bool Heap::isValidAllocation(size_t)
1374 {
1375     if (!isValidThreadState(m_vm))
1376         return false;
1377
1378     if (m_operationInProgress != NoOperation)
1379         return false;
1380     
1381     return true;
1382 }
1383
1384 void Heap::addFinalizer(JSCell* cell, Finalizer finalizer)
1385 {
1386     WeakSet::allocate(*cell, &m_finalizerOwner, reinterpret_cast<void*>(finalizer)); // Balanced by FinalizerOwner::finalize().
1387 }
1388
1389 void Heap::FinalizerOwner::finalize(JSCell*& cell, void* context)
1390 {
1391     Finalizer finalizer = reinterpret_cast<Finalizer>(context);
1392     finalizer(cell);
1393     WeakSet::deallocate(WeakImpl::asWeakImpl(&cell));
1394 }
1395
1396 void Heap::addExecutable(ExecutableBase* executable)
1397 {
1398     m_executables.append(executable);
1399 }
1400
1401 void Heap::collectAllGarbageIfNotDoneRecently()
1402 {
1403     if (!m_fullActivityCallback) {
1404         collectAllGarbage();
1405         return;
1406     }
1407
1408     if (m_fullActivityCallback->didSyncGCRecently()) {
1409         // A synchronous GC was already requested recently so we merely accelerate next collection.
1410         reportAbandonedObjectGraph();
1411         return;
1412     }
1413
1414     m_fullActivityCallback->setDidSyncGCRecently();
1415     collectAllGarbage();
1416 }
1417
1418 class Zombify : public MarkedBlock::VoidFunctor {
1419 public:
1420     inline void visit(JSCell* cell)
1421     {
1422         void** current = reinterpret_cast<void**>(cell);
1423
1424         // We want to maintain zapped-ness because that's how we know if we've called 
1425         // the destructor.
1426         if (cell->isZapped())
1427             current++;
1428
1429         void* limit = static_cast<void*>(reinterpret_cast<char*>(cell) + MarkedBlock::blockFor(cell)->cellSize());
1430         for (; current < limit; current++)
1431             *current = zombifiedBits;
1432     }
1433     IterationStatus operator()(JSCell* cell)
1434     {
1435         visit(cell);
1436         return IterationStatus::Continue;
1437     }
1438 };
1439
1440 void Heap::zombifyDeadObjects()
1441 {
1442     // Sweep now because destructors will crash once we're zombified.
1443     {
1444         SamplingRegion samplingRegion("Garbage Collection: Sweeping");
1445         m_objectSpace.zombifySweep();
1446     }
1447     HeapIterationScope iterationScope(*this);
1448     m_objectSpace.forEachDeadCell<Zombify>(iterationScope);
1449 }
1450
1451 void Heap::flushWriteBarrierBuffer(JSCell* cell)
1452 {
1453 #if ENABLE(GGC)
1454     m_writeBarrierBuffer.flush(*this);
1455     m_writeBarrierBuffer.add(cell);
1456 #else
1457     UNUSED_PARAM(cell);
1458 #endif
1459 }
1460
1461 bool Heap::shouldDoFullCollection(HeapOperation requestedCollectionType) const
1462 {
1463 #if ENABLE(GGC)
1464     if (Options::alwaysDoFullCollection())
1465         return true;
1466
1467     switch (requestedCollectionType) {
1468     case EdenCollection:
1469         return false;
1470     case FullCollection:
1471         return true;
1472     case AnyCollection:
1473         return m_shouldDoFullCollection;
1474     default:
1475         RELEASE_ASSERT_NOT_REACHED();
1476         return false;
1477     }
1478     RELEASE_ASSERT_NOT_REACHED();
1479     return false;
1480 #else
1481     UNUSED_PARAM(requestedCollectionType);
1482     return true;
1483 #endif
1484 }
1485
1486 void Heap::addLogicallyEmptyWeakBlock(WeakBlock* block)
1487 {
1488     m_logicallyEmptyWeakBlocks.append(block);
1489 }
1490
1491 void Heap::sweepAllLogicallyEmptyWeakBlocks()
1492 {
1493     if (m_logicallyEmptyWeakBlocks.isEmpty())
1494         return;
1495
1496     m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0;
1497     while (sweepNextLogicallyEmptyWeakBlock()) { }
1498 }
1499
1500 bool Heap::sweepNextLogicallyEmptyWeakBlock()
1501 {
1502     if (m_indexOfNextLogicallyEmptyWeakBlockToSweep == WTF::notFound)
1503         return false;
1504
1505     WeakBlock* block = m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep];
1506
1507     block->sweep();
1508     if (block->isEmpty()) {
1509         std::swap(m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep], m_logicallyEmptyWeakBlocks.last());
1510         m_logicallyEmptyWeakBlocks.removeLast();
1511         WeakBlock::destroy(block);
1512     } else
1513         m_indexOfNextLogicallyEmptyWeakBlockToSweep++;
1514
1515     if (m_indexOfNextLogicallyEmptyWeakBlockToSweep >= m_logicallyEmptyWeakBlocks.size()) {
1516         m_indexOfNextLogicallyEmptyWeakBlockToSweep = WTF::notFound;
1517         return false;
1518     }
1519
1520     return true;
1521 }
1522
1523 } // namespace JSC