2ed9517f8dcd644482de9ec200cd8cae9b9dd765
[WebKit-https.git] / Source / JavaScriptCore / heap / Heap.cpp
1 /*
2  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2013 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 "GCActivityCallback.h"
31 #include "GCIncomingRefCountedSetInlines.h"
32 #include "HeapRootVisitor.h"
33 #include "HeapStatistics.h"
34 #include "IncrementalSweeper.h"
35 #include "Interpreter.h"
36 #include "VM.h"
37 #include "JSGlobalObject.h"
38 #include "JSLock.h"
39 #include "JSONObject.h"
40 #include "Operations.h"
41 #include "Tracing.h"
42 #include "UnlinkedCodeBlock.h"
43 #include "WeakSetInlines.h"
44 #include <algorithm>
45 #include <wtf/RAMSize.h>
46 #include <wtf/CurrentTime.h>
47
48 using namespace std;
49 using namespace JSC;
50
51 namespace JSC {
52
53 namespace { 
54
55 static const size_t largeHeapSize = 32 * MB; // About 1.5X the average webpage.
56 static const size_t smallHeapSize = 1 * MB; // Matches the FastMalloc per-thread cache.
57
58 #if ENABLE(GC_LOGGING)
59 #if COMPILER(CLANG)
60 #define DEFINE_GC_LOGGING_GLOBAL(type, name, arguments) \
61 _Pragma("clang diagnostic push") \
62 _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \
63 _Pragma("clang diagnostic ignored \"-Wexit-time-destructors\"") \
64 static type name arguments; \
65 _Pragma("clang diagnostic pop")
66 #else
67 #define DEFINE_GC_LOGGING_GLOBAL(type, name, arguments) \
68 static type name arguments;
69 #endif // COMPILER(CLANG)
70
71 struct GCTimer {
72     GCTimer(const char* name)
73         : m_time(0)
74         , m_min(100000000)
75         , m_max(0)
76         , m_count(0)
77         , m_name(name)
78     {
79     }
80     ~GCTimer()
81     {
82         dataLogF("%s: %.2lfms (avg. %.2lf, min. %.2lf, max. %.2lf)\n", m_name, m_time * 1000, m_time * 1000 / m_count, m_min*1000, m_max*1000);
83     }
84     double m_time;
85     double m_min;
86     double m_max;
87     size_t m_count;
88     const char* m_name;
89 };
90
91 struct GCTimerScope {
92     GCTimerScope(GCTimer* timer)
93         : m_timer(timer)
94         , m_start(WTF::monotonicallyIncreasingTime())
95     {
96     }
97     ~GCTimerScope()
98     {
99         double delta = WTF::monotonicallyIncreasingTime() - m_start;
100         if (delta < m_timer->m_min)
101             m_timer->m_min = delta;
102         if (delta > m_timer->m_max)
103             m_timer->m_max = delta;
104         m_timer->m_count++;
105         m_timer->m_time += delta;
106     }
107     GCTimer* m_timer;
108     double m_start;
109 };
110
111 struct GCCounter {
112     GCCounter(const char* name)
113         : m_name(name)
114         , m_count(0)
115         , m_total(0)
116         , m_min(10000000)
117         , m_max(0)
118     {
119     }
120     
121     void count(size_t amount)
122     {
123         m_count++;
124         m_total += amount;
125         if (amount < m_min)
126             m_min = amount;
127         if (amount > m_max)
128             m_max = amount;
129     }
130     ~GCCounter()
131     {
132         dataLogF("%s: %zu values (avg. %zu, min. %zu, max. %zu)\n", m_name, m_total, m_total / m_count, m_min, m_max);
133     }
134     const char* m_name;
135     size_t m_count;
136     size_t m_total;
137     size_t m_min;
138     size_t m_max;
139 };
140
141 #define GCPHASE(name) DEFINE_GC_LOGGING_GLOBAL(GCTimer, name##Timer, (#name)); GCTimerScope name##TimerScope(&name##Timer)
142 #define COND_GCPHASE(cond, name1, name2) DEFINE_GC_LOGGING_GLOBAL(GCTimer, name1##Timer, (#name1)); DEFINE_GC_LOGGING_GLOBAL(GCTimer, name2##Timer, (#name2)); GCTimerScope name1##CondTimerScope(cond ? &name1##Timer : &name2##Timer)
143 #define GCCOUNTER(name, value) do { DEFINE_GC_LOGGING_GLOBAL(GCCounter, name##Counter, (#name)); name##Counter.count(value); } while (false)
144     
145 #else
146
147 #define GCPHASE(name) do { } while (false)
148 #define COND_GCPHASE(cond, name1, name2) do { } while (false)
149 #define GCCOUNTER(name, value) do { } while (false)
150 #endif
151
152 static inline size_t minHeapSize(HeapType heapType, size_t ramSize)
153 {
154     if (heapType == LargeHeap)
155         return min(largeHeapSize, ramSize / 4);
156     return smallHeapSize;
157 }
158
159 static inline size_t proportionalHeapSize(size_t heapSize, size_t ramSize)
160 {
161     // Try to stay under 1/2 RAM size to leave room for the DOM, rendering, networking, etc.
162     if (heapSize < ramSize / 4)
163         return 2 * heapSize;
164     if (heapSize < ramSize / 2)
165         return 1.5 * heapSize;
166     return 1.25 * heapSize;
167 }
168
169 static inline bool isValidSharedInstanceThreadState(VM* vm)
170 {
171     return vm->currentThreadIsHoldingAPILock();
172 }
173
174 static inline bool isValidThreadState(VM* vm)
175 {
176     if (vm->identifierTable != wtfThreadData().currentIdentifierTable())
177         return false;
178
179     if (vm->isSharedInstance() && !isValidSharedInstanceThreadState(vm))
180         return false;
181
182     return true;
183 }
184
185 struct MarkObject : public MarkedBlock::VoidFunctor {
186     void operator()(JSCell* cell)
187     {
188         if (cell->isZapped())
189             return;
190         Heap::heap(cell)->setMarked(cell);
191     }
192 };
193
194 struct Count : public MarkedBlock::CountFunctor {
195     void operator()(JSCell*) { count(1); }
196 };
197
198 struct CountIfGlobalObject : MarkedBlock::CountFunctor {
199     void operator()(JSCell* cell) {
200         if (!cell->isObject())
201             return;
202         if (!asObject(cell)->isGlobalObject())
203             return;
204         count(1);
205     }
206 };
207
208 class RecordType {
209 public:
210     typedef PassOwnPtr<TypeCountSet> ReturnType;
211
212     RecordType();
213     void operator()(JSCell*);
214     ReturnType returnValue();
215
216 private:
217     const char* typeName(JSCell*);
218     OwnPtr<TypeCountSet> m_typeCountSet;
219 };
220
221 inline RecordType::RecordType()
222     : m_typeCountSet(adoptPtr(new TypeCountSet))
223 {
224 }
225
226 inline const char* RecordType::typeName(JSCell* cell)
227 {
228     const ClassInfo* info = cell->classInfo();
229     if (!info || !info->className)
230         return "[unknown]";
231     return info->className;
232 }
233
234 inline void RecordType::operator()(JSCell* cell)
235 {
236     m_typeCountSet->add(typeName(cell));
237 }
238
239 inline PassOwnPtr<TypeCountSet> RecordType::returnValue()
240 {
241     return m_typeCountSet.release();
242 }
243
244 } // anonymous namespace
245
246 Heap::Heap(VM* vm, HeapType heapType)
247     : m_heapType(heapType)
248     , m_ramSize(ramSize())
249     , m_minBytesPerCycle(minHeapSize(m_heapType, m_ramSize))
250     , m_sizeAfterLastCollect(0)
251     , m_bytesAllocatedLimit(m_minBytesPerCycle)
252     , m_bytesAllocated(0)
253     , m_bytesAbandoned(0)
254     , m_operationInProgress(NoOperation)
255     , m_blockAllocator()
256     , m_objectSpace(this)
257     , m_storageSpace(this)
258     , m_extraMemoryUsage(0)
259     , m_machineThreads(this)
260     , m_sharedData(vm)
261     , m_slotVisitor(m_sharedData)
262     , m_copyVisitor(m_sharedData)
263     , m_handleSet(vm)
264     , m_isSafeToCollect(false)
265     , m_vm(vm)
266     , m_lastGCLength(0)
267     , m_lastCodeDiscardTime(WTF::monotonicallyIncreasingTime())
268     , m_activityCallback(DefaultGCActivityCallback::create(this))
269     , m_sweeper(IncrementalSweeper::create(this))
270     , m_deferralDepth(0)
271 {
272     m_storageSpace.init();
273 }
274
275 Heap::~Heap()
276 {
277 }
278
279 bool Heap::isPagedOut(double deadline)
280 {
281     return m_objectSpace.isPagedOut(deadline) || m_storageSpace.isPagedOut(deadline);
282 }
283
284 // The VM is being destroyed and the collector will never run again.
285 // Run all pending finalizers now because we won't get another chance.
286 void Heap::lastChanceToFinalize()
287 {
288     RELEASE_ASSERT(!m_vm->dynamicGlobalObject);
289     RELEASE_ASSERT(m_operationInProgress == NoOperation);
290
291     m_objectSpace.lastChanceToFinalize();
292
293 #if ENABLE(SIMPLE_HEAP_PROFILING)
294     m_slotVisitor.m_visitedTypeCounts.dump(WTF::dataFile(), "Visited Type Counts");
295     m_destroyedTypeCounts.dump(WTF::dataFile(), "Destroyed Type Counts");
296 #endif
297 }
298
299 void Heap::reportExtraMemoryCostSlowCase(size_t cost)
300 {
301     // Our frequency of garbage collection tries to balance memory use against speed
302     // by collecting based on the number of newly created values. However, for values
303     // that hold on to a great deal of memory that's not in the form of other JS values,
304     // that is not good enough - in some cases a lot of those objects can pile up and
305     // use crazy amounts of memory without a GC happening. So we track these extra
306     // memory costs. Only unusually large objects are noted, and we only keep track
307     // of this extra cost until the next GC. In garbage collected languages, most values
308     // are either very short lived temporaries, or have extremely long lifetimes. So
309     // if a large value survives one garbage collection, there is not much point to
310     // collecting more frequently as long as it stays alive.
311
312     didAllocate(cost);
313     collectIfNecessaryOrDefer();
314 }
315
316 void Heap::reportAbandonedObjectGraph()
317 {
318     // Our clients don't know exactly how much memory they
319     // are abandoning so we just guess for them.
320     double abandonedBytes = 0.10 * m_sizeAfterLastCollect;
321
322     // We want to accelerate the next collection. Because memory has just 
323     // been abandoned, the next collection has the potential to 
324     // be more profitable. Since allocation is the trigger for collection, 
325     // we hasten the next collection by pretending that we've allocated more memory. 
326     didAbandon(abandonedBytes);
327 }
328
329 void Heap::didAbandon(size_t bytes)
330 {
331     m_activityCallback->didAllocate(m_bytesAllocated + m_bytesAbandoned);
332     m_bytesAbandoned += bytes;
333 }
334
335 void Heap::protect(JSValue k)
336 {
337     ASSERT(k);
338     ASSERT(m_vm->currentThreadIsHoldingAPILock());
339
340     if (!k.isCell())
341         return;
342
343     m_protectedValues.add(k.asCell());
344 }
345
346 bool Heap::unprotect(JSValue k)
347 {
348     ASSERT(k);
349     ASSERT(m_vm->currentThreadIsHoldingAPILock());
350
351     if (!k.isCell())
352         return false;
353
354     return m_protectedValues.remove(k.asCell());
355 }
356
357 void Heap::jettisonDFGCodeBlock(PassRefPtr<CodeBlock> codeBlock)
358 {
359     m_dfgCodeBlocks.jettison(codeBlock);
360 }
361
362 void Heap::addReference(JSCell* cell, ArrayBuffer* buffer)
363 {
364     if (m_arrayBuffers.addReference(cell, buffer)) {
365         collectIfNecessaryOrDefer();
366         didAllocate(buffer->gcSizeEstimateInBytes());
367     }
368 }
369
370 void Heap::markProtectedObjects(HeapRootVisitor& heapRootVisitor)
371 {
372     ProtectCountSet::iterator end = m_protectedValues.end();
373     for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
374         heapRootVisitor.visit(&it->key);
375 }
376
377 void Heap::pushTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>* tempVector)
378 {
379     m_tempSortingVectors.append(tempVector);
380 }
381
382 void Heap::popTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>* tempVector)
383 {
384     ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last());
385     m_tempSortingVectors.removeLast();
386 }
387
388 void Heap::markTempSortVectors(HeapRootVisitor& heapRootVisitor)
389 {
390     typedef Vector<Vector<ValueStringPair, 0, UnsafeVectorOverflow>* > VectorOfValueStringVectors;
391
392     VectorOfValueStringVectors::iterator end = m_tempSortingVectors.end();
393     for (VectorOfValueStringVectors::iterator it = m_tempSortingVectors.begin(); it != end; ++it) {
394         Vector<ValueStringPair, 0, UnsafeVectorOverflow>* tempSortingVector = *it;
395
396         Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end();
397         for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt) {
398             if (vectorIt->first)
399                 heapRootVisitor.visit(&vectorIt->first);
400         }
401     }
402 }
403
404 void Heap::harvestWeakReferences()
405 {
406     m_slotVisitor.harvestWeakReferences();
407 }
408
409 void Heap::finalizeUnconditionalFinalizers()
410 {
411     m_slotVisitor.finalizeUnconditionalFinalizers();
412 }
413
414 inline JSStack& Heap::stack()
415 {
416     return m_vm->interpreter->stack();
417 }
418
419 void Heap::canonicalizeCellLivenessData()
420 {
421     m_objectSpace.canonicalizeCellLivenessData();
422 }
423
424 void Heap::getConservativeRegisterRoots(HashSet<JSCell*>& roots)
425 {
426     ASSERT(isValidThreadState(m_vm));
427     ConservativeRoots stackRoots(&m_objectSpace.blocks(), &m_storageSpace);
428     stack().gatherConservativeRoots(stackRoots);
429     size_t stackRootCount = stackRoots.size();
430     JSCell** registerRoots = stackRoots.roots();
431     for (size_t i = 0; i < stackRootCount; i++) {
432         setMarked(registerRoots[i]);
433         roots.add(registerRoots[i]);
434     }
435 }
436
437 void Heap::markRoots()
438 {
439     SamplingRegion samplingRegion("Garbage Collection: Tracing");
440
441     GCPHASE(MarkRoots);
442     ASSERT(isValidThreadState(m_vm));
443
444 #if ENABLE(OBJECT_MARK_LOGGING)
445     double gcStartTime = WTF::monotonicallyIncreasingTime();
446 #endif
447
448     void* dummy;
449     
450     // We gather conservative roots before clearing mark bits because conservative
451     // gathering uses the mark bits to determine whether a reference is valid.
452     ConservativeRoots machineThreadRoots(&m_objectSpace.blocks(), &m_storageSpace);
453     m_jitStubRoutines.clearMarks();
454     {
455         GCPHASE(GatherConservativeRoots);
456         m_machineThreads.gatherConservativeRoots(machineThreadRoots, &dummy);
457     }
458
459     ConservativeRoots stackRoots(&m_objectSpace.blocks(), &m_storageSpace);
460     m_dfgCodeBlocks.clearMarks();
461     {
462         GCPHASE(GatherStackRoots);
463         stack().gatherConservativeRoots(
464             stackRoots, m_jitStubRoutines, m_dfgCodeBlocks);
465     }
466
467 #if ENABLE(DFG_JIT)
468     ConservativeRoots scratchBufferRoots(&m_objectSpace.blocks(), &m_storageSpace);
469     {
470         GCPHASE(GatherScratchBufferRoots);
471         m_vm->gatherConservativeRoots(scratchBufferRoots);
472     }
473 #endif
474
475     {
476         GCPHASE(clearMarks);
477         m_objectSpace.clearMarks();
478     }
479
480     m_sharedData.didStartMarking();
481     SlotVisitor& visitor = m_slotVisitor;
482     visitor.setup();
483     HeapRootVisitor heapRootVisitor(visitor);
484
485     {
486         ParallelModeEnabler enabler(visitor);
487
488         if (m_vm->codeBlocksBeingCompiled.size()) {
489             GCPHASE(VisitActiveCodeBlock);
490             for (size_t i = 0; i < m_vm->codeBlocksBeingCompiled.size(); i++)
491                 m_vm->codeBlocksBeingCompiled[i]->visitAggregate(visitor);
492         }
493
494         m_vm->smallStrings.visitStrongReferences(visitor);
495
496         {
497             GCPHASE(VisitMachineRoots);
498             MARK_LOG_ROOT(visitor, "C++ Stack");
499             visitor.append(machineThreadRoots);
500             visitor.donateAndDrain();
501         }
502         {
503             GCPHASE(VisitStackRoots);
504             MARK_LOG_ROOT(visitor, "Stack");
505             visitor.append(stackRoots);
506             visitor.donateAndDrain();
507         }
508 #if ENABLE(DFG_JIT)
509         {
510             GCPHASE(VisitScratchBufferRoots);
511             MARK_LOG_ROOT(visitor, "Scratch Buffers");
512             visitor.append(scratchBufferRoots);
513             visitor.donateAndDrain();
514         }
515 #endif
516         {
517             GCPHASE(VisitProtectedObjects);
518             MARK_LOG_ROOT(visitor, "Protected Objects");
519             markProtectedObjects(heapRootVisitor);
520             visitor.donateAndDrain();
521         }
522         {
523             GCPHASE(VisitTempSortVectors);
524             MARK_LOG_ROOT(visitor, "Temp Sort Vectors");
525             markTempSortVectors(heapRootVisitor);
526             visitor.donateAndDrain();
527         }
528
529         {
530             GCPHASE(MarkingArgumentBuffers);
531             if (m_markListSet && m_markListSet->size()) {
532                 MARK_LOG_ROOT(visitor, "Argument Buffers");
533                 MarkedArgumentBuffer::markLists(heapRootVisitor, *m_markListSet);
534                 visitor.donateAndDrain();
535             }
536         }
537         if (m_vm->exception) {
538             GCPHASE(MarkingException);
539             MARK_LOG_ROOT(visitor, "Exceptions");
540             heapRootVisitor.visit(&m_vm->exception);
541             visitor.donateAndDrain();
542         }
543     
544         {
545             GCPHASE(VisitStrongHandles);
546             MARK_LOG_ROOT(visitor, "Strong Handles");
547             m_handleSet.visitStrongHandles(heapRootVisitor);
548             visitor.donateAndDrain();
549         }
550     
551         {
552             GCPHASE(HandleStack);
553             MARK_LOG_ROOT(visitor, "Handle Stack");
554             m_handleStack.visit(heapRootVisitor);
555             visitor.donateAndDrain();
556         }
557     
558         {
559             GCPHASE(TraceCodeBlocksAndJITStubRoutines);
560             MARK_LOG_ROOT(visitor, "Trace Code Blocks and JIT Stub Routines");
561             m_dfgCodeBlocks.traceMarkedCodeBlocks(visitor);
562             m_jitStubRoutines.traceMarkedStubRoutines(visitor);
563             visitor.donateAndDrain();
564         }
565     
566 #if ENABLE(PARALLEL_GC)
567         {
568             GCPHASE(Convergence);
569             visitor.drainFromShared(SlotVisitor::MasterDrain);
570         }
571 #endif
572     }
573
574     // Weak references must be marked last because their liveness depends on
575     // the liveness of the rest of the object graph.
576     {
577         GCPHASE(VisitingLiveWeakHandles);
578         MARK_LOG_ROOT(visitor, "Live Weak Handles");
579         while (true) {
580             m_objectSpace.visitWeakSets(heapRootVisitor);
581             harvestWeakReferences();
582             if (visitor.isEmpty())
583                 break;
584             {
585                 ParallelModeEnabler enabler(visitor);
586                 visitor.donateAndDrain();
587 #if ENABLE(PARALLEL_GC)
588                 visitor.drainFromShared(SlotVisitor::MasterDrain);
589 #endif
590             }
591         }
592     }
593
594     GCCOUNTER(VisitedValueCount, visitor.visitCount());
595
596     m_sharedData.didFinishMarking();
597 #if ENABLE(OBJECT_MARK_LOGGING)
598     size_t visitCount = visitor.visitCount();
599 #if ENABLE(PARALLEL_GC)
600     visitCount += m_sharedData.childVisitCount();
601 #endif
602     MARK_LOG_MESSAGE2("\nNumber of live Objects after full GC %lu, took %.6f secs\n", visitCount, WTF::monotonicallyIncreasingTime() - gcStartTime);
603 #endif
604
605     visitor.reset();
606 #if ENABLE(PARALLEL_GC)
607     m_sharedData.resetChildren();
608 #endif
609     m_sharedData.reset();
610 }
611
612 void Heap::copyBackingStores()
613 {
614     m_storageSpace.startedCopying();
615     if (m_storageSpace.shouldDoCopyPhase()) {
616         m_sharedData.didStartCopying();
617         m_copyVisitor.startCopying();
618         m_copyVisitor.copyFromShared();
619         m_copyVisitor.doneCopying();
620         // We need to wait for everybody to finish and return their CopiedBlocks 
621         // before signaling that the phase is complete.
622         m_storageSpace.doneCopying();
623         m_sharedData.didFinishCopying();
624     } else 
625         m_storageSpace.doneCopying();
626 }
627
628 size_t Heap::objectCount()
629 {
630     return m_objectSpace.objectCount();
631 }
632
633 size_t Heap::extraSize()
634 {
635     return m_extraMemoryUsage + m_arrayBuffers.size();
636 }
637
638 size_t Heap::size()
639 {
640     return m_objectSpace.size() + m_storageSpace.size() + extraSize();
641 }
642
643 size_t Heap::capacity()
644 {
645     return m_objectSpace.capacity() + m_storageSpace.capacity() + extraSize();
646 }
647
648 size_t Heap::protectedGlobalObjectCount()
649 {
650     return forEachProtectedCell<CountIfGlobalObject>();
651 }
652
653 size_t Heap::globalObjectCount()
654 {
655     return m_objectSpace.forEachLiveCell<CountIfGlobalObject>();
656 }
657
658 size_t Heap::protectedObjectCount()
659 {
660     return forEachProtectedCell<Count>();
661 }
662
663 PassOwnPtr<TypeCountSet> Heap::protectedObjectTypeCounts()
664 {
665     return forEachProtectedCell<RecordType>();
666 }
667
668 PassOwnPtr<TypeCountSet> Heap::objectTypeCounts()
669 {
670     return m_objectSpace.forEachLiveCell<RecordType>();
671 }
672
673 void Heap::deleteAllCompiledCode()
674 {
675     // If JavaScript is running, it's not safe to delete code, since we'll end
676     // up deleting code that is live on the stack.
677     if (m_vm->dynamicGlobalObject)
678         return;
679
680     for (ExecutableBase* current = m_compiledCode.head(); current; current = current->next()) {
681         if (!current->isFunctionExecutable())
682             continue;
683         static_cast<FunctionExecutable*>(current)->clearCodeIfNotCompiling();
684     }
685
686     m_dfgCodeBlocks.clearMarks();
687     m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks();
688 }
689
690 void Heap::deleteUnmarkedCompiledCode()
691 {
692     ExecutableBase* next;
693     for (ExecutableBase* current = m_compiledCode.head(); current; current = next) {
694         next = current->next();
695         if (isMarked(current))
696             continue;
697
698         // We do this because executable memory is limited on some platforms and because
699         // CodeBlock requires eager finalization.
700         ExecutableBase::clearCodeVirtual(current);
701         m_compiledCode.remove(current);
702     }
703
704     m_dfgCodeBlocks.deleteUnmarkedJettisonedCodeBlocks();
705     m_jitStubRoutines.deleteUnmarkedJettisonedStubRoutines();
706 }
707
708 void Heap::collectAllGarbage()
709 {
710     if (!m_isSafeToCollect)
711         return;
712     
713     collect(DoSweep);
714 }
715
716 static double minute = 60.0;
717
718 void Heap::collect(SweepToggle sweepToggle)
719 {
720 #if ENABLE(ALLOCATION_LOGGING)
721     dataLogF("JSC GC starting collection.\n");
722 #endif
723     
724     double before = 0;
725     if (Options::logGC()) {
726         dataLog("[GC", sweepToggle == DoSweep ? " (eager sweep)" : "", ": ");
727         before = currentTimeMS();
728     }
729     
730     SamplingRegion samplingRegion("Garbage Collection");
731     
732     RELEASE_ASSERT(!m_deferralDepth);
733     GCPHASE(Collect);
734     ASSERT(vm()->currentThreadIsHoldingAPILock());
735     RELEASE_ASSERT(vm()->identifierTable == wtfThreadData().currentIdentifierTable());
736     ASSERT(m_isSafeToCollect);
737     JAVASCRIPTCORE_GC_BEGIN();
738     RELEASE_ASSERT(m_operationInProgress == NoOperation);
739     
740     m_deferralDepth++; // Make sure that we don't GC in this call.
741     m_vm->prepareToDiscardCode();
742     m_deferralDepth--; // Decrement deferal manually, so we don't GC when we do so, since we are already GCing!.
743     
744     m_operationInProgress = Collection;
745     m_extraMemoryUsage = 0;
746
747     m_activityCallback->willCollect();
748
749     double lastGCStartTime = WTF::monotonicallyIncreasingTime();
750     if (lastGCStartTime - m_lastCodeDiscardTime > minute) {
751         deleteAllCompiledCode();
752         m_lastCodeDiscardTime = WTF::monotonicallyIncreasingTime();
753     }
754
755     {
756         GCPHASE(Canonicalize);
757         m_objectSpace.canonicalizeCellLivenessData();
758     }
759
760     markRoots();
761     
762     {
763         GCPHASE(ReapingWeakHandles);
764         m_objectSpace.reapWeakSets();
765     }
766
767     JAVASCRIPTCORE_GC_MARKED();
768     
769     {
770         GCPHASE(SweepingArrayBuffers);
771         m_arrayBuffers.sweep();
772     }
773
774     {
775         m_blockSnapshot.resize(m_objectSpace.blocks().set().size());
776         MarkedBlockSnapshotFunctor functor(m_blockSnapshot);
777         m_objectSpace.forEachBlock(functor);
778     }
779
780     copyBackingStores();
781
782     {
783         GCPHASE(FinalizeUnconditionalFinalizers);
784         finalizeUnconditionalFinalizers();
785     }
786
787     {
788         GCPHASE(DeleteCodeBlocks);
789         deleteUnmarkedCompiledCode();
790     }
791
792     {
793         GCPHASE(DeleteSourceProviderCaches);
794         m_vm->clearSourceProviderCaches();
795     }
796
797     if (sweepToggle == DoSweep) {
798         SamplingRegion samplingRegion("Garbage Collection: Sweeping");
799         GCPHASE(Sweeping);
800         m_objectSpace.sweep();
801         m_objectSpace.shrink();
802     }
803
804     m_sweeper->startSweeping(m_blockSnapshot);
805     m_bytesAbandoned = 0;
806
807     {
808         GCPHASE(ResetAllocators);
809         m_objectSpace.resetAllocators();
810     }
811     
812     size_t currentHeapSize = size();
813     if (Options::gcMaxHeapSize() && currentHeapSize > Options::gcMaxHeapSize())
814         HeapStatistics::exitWithFailure();
815
816     m_sizeAfterLastCollect = currentHeapSize;
817
818     // To avoid pathological GC churn in very small and very large heaps, we set
819     // the new allocation limit based on the current size of the heap, with a
820     // fixed minimum.
821     size_t maxHeapSize = max(minHeapSize(m_heapType, m_ramSize), proportionalHeapSize(currentHeapSize, m_ramSize));
822     m_bytesAllocatedLimit = maxHeapSize - currentHeapSize;
823
824     m_bytesAllocated = 0;
825     double lastGCEndTime = WTF::monotonicallyIncreasingTime();
826     m_lastGCLength = lastGCEndTime - lastGCStartTime;
827
828     if (Options::recordGCPauseTimes())
829         HeapStatistics::recordGCPauseTime(lastGCStartTime, lastGCEndTime);
830     RELEASE_ASSERT(m_operationInProgress == Collection);
831
832     m_operationInProgress = NoOperation;
833     JAVASCRIPTCORE_GC_END();
834
835     if (Options::useZombieMode())
836         zombifyDeadObjects();
837
838     if (Options::objectsAreImmortal())
839         markDeadObjects();
840
841     if (Options::showObjectStatistics())
842         HeapStatistics::showObjectStatistics(this);
843     
844     if (Options::logGC()) {
845         double after = currentTimeMS();
846         dataLog(after - before, " ms, ", currentHeapSize / 1024, " kb]\n");
847     }
848
849 #if ENABLE(ALLOCATION_LOGGING)
850     dataLogF("JSC GC finishing collection.\n");
851 #endif
852 }
853
854 bool Heap::collectIfNecessaryOrDefer()
855 {
856     if (m_deferralDepth)
857         return false;
858     
859     if (!shouldCollect())
860         return false;
861     
862     collect(DoNotSweep);
863     return true;
864 }
865
866 void Heap::markDeadObjects()
867 {
868     m_objectSpace.forEachDeadCell<MarkObject>();
869 }
870
871 void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback)
872 {
873     m_activityCallback = activityCallback;
874 }
875
876 GCActivityCallback* Heap::activityCallback()
877 {
878     return m_activityCallback.get();
879 }
880
881 IncrementalSweeper* Heap::sweeper()
882 {
883     return m_sweeper.get();
884 }
885
886 void Heap::setGarbageCollectionTimerEnabled(bool enable)
887 {
888     activityCallback()->setEnabled(enable);
889 }
890
891 void Heap::didAllocate(size_t bytes)
892 {
893     m_activityCallback->didAllocate(m_bytesAllocated + m_bytesAbandoned);
894     m_bytesAllocated += bytes;
895 }
896
897 bool Heap::isValidAllocation(size_t)
898 {
899     if (!isValidThreadState(m_vm))
900         return false;
901
902     if (m_operationInProgress != NoOperation)
903         return false;
904     
905     return true;
906 }
907
908 void Heap::addFinalizer(JSCell* cell, Finalizer finalizer)
909 {
910     WeakSet::allocate(cell, &m_finalizerOwner, reinterpret_cast<void*>(finalizer)); // Balanced by FinalizerOwner::finalize().
911 }
912
913 void Heap::FinalizerOwner::finalize(Handle<Unknown> handle, void* context)
914 {
915     HandleSlot slot = handle.slot();
916     Finalizer finalizer = reinterpret_cast<Finalizer>(context);
917     finalizer(slot->asCell());
918     WeakSet::deallocate(WeakImpl::asWeakImpl(slot));
919 }
920
921 void Heap::addCompiledCode(ExecutableBase* executable)
922 {
923     m_compiledCode.append(executable);
924 }
925
926 class Zombify : public MarkedBlock::VoidFunctor {
927 public:
928     void operator()(JSCell* cell)
929     {
930         void** current = reinterpret_cast<void**>(cell);
931
932         // We want to maintain zapped-ness because that's how we know if we've called 
933         // the destructor.
934         if (cell->isZapped())
935             current++;
936
937         void* limit = static_cast<void*>(reinterpret_cast<char*>(cell) + MarkedBlock::blockFor(cell)->cellSize());
938         for (; current < limit; current++)
939             *current = reinterpret_cast<void*>(0xbbadbeef);
940     }
941 };
942
943 void Heap::zombifyDeadObjects()
944 {
945     // Sweep now because destructors will crash once we're zombified.
946     m_objectSpace.sweep();
947     m_objectSpace.forEachDeadCell<Zombify>();
948 }
949
950 void Heap::incrementDeferralDepth()
951 {
952     RELEASE_ASSERT(m_deferralDepth < 100); // Sanity check to make sure this doesn't get ridiculous.
953     
954     m_deferralDepth++;
955 }
956
957 void Heap::decrementDeferralDepth()
958 {
959     RELEASE_ASSERT(m_deferralDepth >= 1);
960     
961     m_deferralDepth--;
962 }
963
964 void Heap::decrementDeferralDepthAndGCIfNeeded()
965 {
966     decrementDeferralDepth();
967     collectIfNecessaryOrDefer();
968 }
969
970 } // namespace JSC