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