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