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