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