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