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