Build fix: removed some uses of nextNumber that I missed last time.
[WebKit-https.git] / Source / JavaScriptCore / runtime / Heap.cpp
1 /*
2  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 "ArgList.h"
25 #include "CallFrame.h"
26 #include "CodeBlock.h"
27 #include "CollectorHeapIterator.h"
28 #include "GCActivityCallback.h"
29 #include "Interpreter.h"
30 #include "JSArray.h"
31 #include "JSGlobalObject.h"
32 #include "JSLock.h"
33 #include "JSONObject.h"
34 #include "JSString.h"
35 #include "JSValue.h"
36 #include "JSZombie.h"
37 #include "MarkStack.h"
38 #include "Nodes.h"
39 #include "Tracing.h"
40 #include <algorithm>
41 #include <limits.h>
42 #include <setjmp.h>
43 #include <stdlib.h>
44 #include <wtf/FastMalloc.h>
45 #include <wtf/HashCountedSet.h>
46 #include <wtf/WTFThreadData.h>
47 #include <wtf/UnusedParam.h>
48 #include <wtf/VMTags.h>
49
50 #define COLLECT_ON_EVERY_ALLOCATION 0
51
52 using std::max;
53
54 namespace JSC {
55
56 // tunable parameters
57
58 const size_t GROWTH_FACTOR = 2;
59 const size_t LOW_WATER_FACTOR = 4;
60 const size_t ALLOCATIONS_PER_COLLECTION = 3600;
61 // This value has to be a macro to be used in max() without introducing
62 // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
63 #define MIN_ARRAY_SIZE (static_cast<size_t>(14))
64
65 Heap::Heap(JSGlobalData* globalData)
66     : m_markListSet(0)
67     , m_globalData(globalData)
68     , m_machineStackMarker(this)
69 {
70     ASSERT(globalData);
71     memset(&m_heap, 0, sizeof(CollectorHeap));
72     allocateBlock();
73     m_activityCallback = DefaultGCActivityCallback::create(this);
74     (*m_activityCallback)();
75 }
76
77 Heap::~Heap()
78 {
79     // The destroy function must already have been called, so assert this.
80     ASSERT(!m_globalData);
81 }
82
83 void Heap::destroy()
84 {
85     JSLock lock(SilenceAssertionsOnly);
86
87     if (!m_globalData)
88         return;
89
90     ASSERT(!m_globalData->dynamicGlobalObject);
91     ASSERT(!isBusy());
92     
93     // The global object is not GC protected at this point, so sweeping may delete it
94     // (and thus the global data) before other objects that may use the global data.
95     RefPtr<JSGlobalData> protect(m_globalData);
96
97     delete m_markListSet;
98     m_markListSet = 0;
99
100     freeBlocks();
101
102     m_globalData = 0;
103 }
104
105 NEVER_INLINE CollectorBlock* Heap::allocateBlock()
106 {
107     PageAllocationAligned allocation = PageAllocationAligned::allocate(BLOCK_SIZE, BLOCK_SIZE, OSAllocator::JSGCHeapPages);
108     CollectorBlock* block = static_cast<CollectorBlock*>(allocation.base());
109     if (!block)
110         CRASH();
111
112     // Initialize block.
113
114     block->heap = this;
115     clearMarkBits(block);
116
117     Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get();
118     for (size_t i = 0; i < HeapConstants::cellsPerBlock; ++i)
119         new (&block->cells[i]) JSCell(dummyMarkableCellStructure);
120     
121     // Add block to blocks vector.
122
123     size_t numBlocks = m_heap.numBlocks;
124     if (m_heap.usedBlocks == numBlocks) {
125         static const size_t maxNumBlocks = ULONG_MAX / sizeof(PageAllocationAligned) / GROWTH_FACTOR;
126         if (numBlocks > maxNumBlocks)
127             CRASH();
128         numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR);
129         m_heap.numBlocks = numBlocks;
130         m_heap.blocks = static_cast<PageAllocationAligned*>(fastRealloc(m_heap.blocks, numBlocks * sizeof(PageAllocationAligned)));
131     }
132     m_heap.blocks[m_heap.usedBlocks++] = allocation;
133
134     return block;
135 }
136
137 NEVER_INLINE void Heap::freeBlock(size_t block)
138 {
139     m_heap.didShrink = true;
140
141     ObjectIterator it(m_heap, block);
142     ObjectIterator end(m_heap, block + 1);
143     for ( ; it != end; ++it)
144         (*it)->~JSCell();
145     m_heap.blocks[block].deallocate();
146
147     // swap with the last block so we compact as we go
148     m_heap.blocks[block] = m_heap.blocks[m_heap.usedBlocks - 1];
149     m_heap.usedBlocks--;
150
151     if (m_heap.numBlocks > MIN_ARRAY_SIZE && m_heap.usedBlocks < m_heap.numBlocks / LOW_WATER_FACTOR) {
152         m_heap.numBlocks = m_heap.numBlocks / GROWTH_FACTOR; 
153         m_heap.blocks = static_cast<PageAllocationAligned*>(fastRealloc(m_heap.blocks, m_heap.numBlocks * sizeof(PageAllocationAligned)));
154     }
155 }
156
157 void Heap::freeBlocks()
158 {
159     ProtectCountSet protectedValuesCopy = m_protectedValues;
160
161     clearMarkBits();
162     ProtectCountSet::iterator protectedValuesEnd = protectedValuesCopy.end();
163     for (ProtectCountSet::iterator it = protectedValuesCopy.begin(); it != protectedValuesEnd; ++it)
164         markCell(it->first);
165
166     m_heap.nextCell = 0;
167     m_heap.nextBlock = 0;
168     DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell);
169     DeadObjectIterator end(m_heap, m_heap.usedBlocks);
170     for ( ; it != end; ++it)
171         (*it)->~JSCell();
172
173     ASSERT(!protectedObjectCount());
174
175     protectedValuesEnd = protectedValuesCopy.end();
176     for (ProtectCountSet::iterator it = protectedValuesCopy.begin(); it != protectedValuesEnd; ++it)
177         it->first->~JSCell();
178
179     for (size_t block = 0; block < m_heap.usedBlocks; ++block)
180         m_heap.blocks[block].deallocate();
181
182     fastFree(m_heap.blocks);
183
184     memset(&m_heap, 0, sizeof(CollectorHeap));
185 }
186
187 void Heap::recordExtraCost(size_t cost)
188 {
189     // Our frequency of garbage collection tries to balance memory use against speed
190     // by collecting based on the number of newly created values. However, for values
191     // that hold on to a great deal of memory that's not in the form of other JS values,
192     // that is not good enough - in some cases a lot of those objects can pile up and
193     // use crazy amounts of memory without a GC happening. So we track these extra
194     // memory costs. Only unusually large objects are noted, and we only keep track
195     // of this extra cost until the next GC. In garbage collected languages, most values
196     // are either very short lived temporaries, or have extremely long lifetimes. So
197     // if a large value survives one garbage collection, there is not much point to
198     // collecting more frequently as long as it stays alive.
199
200     if (m_heap.extraCost > maxExtraCost && m_heap.extraCost > m_heap.usedBlocks * BLOCK_SIZE / 2) {
201         // If the last iteration through the heap deallocated blocks, we need
202         // to clean up remaining garbage before marking. Otherwise, the conservative
203         // marking mechanism might follow a pointer to unmapped memory.
204         if (m_heap.didShrink)
205             sweep();
206         reset();
207     }
208     m_heap.extraCost += cost;
209 }
210
211 void* Heap::allocate(size_t s)
212 {
213     ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
214     typedef HeapConstants::Block Block;
215     typedef HeapConstants::Cell Cell;
216     
217     ASSERT(JSLock::lockCount() > 0);
218     ASSERT(JSLock::currentThreadIsHoldingLock());
219     ASSERT_UNUSED(s, s <= HeapConstants::cellSize);
220
221     ASSERT(m_heap.operationInProgress == NoOperation);
222
223 #if COLLECT_ON_EVERY_ALLOCATION
224     collectAllGarbage();
225     ASSERT(m_heap.operationInProgress == NoOperation);
226 #endif
227
228 allocate:
229
230     // Fast case: find the next garbage cell and recycle it.
231
232     do {
233         ASSERT(m_heap.nextBlock < m_heap.usedBlocks);
234         Block* block = m_heap.collectorBlock(m_heap.nextBlock);
235         do {
236             ASSERT(m_heap.nextCell < HeapConstants::cellsPerBlock);
237             if (!block->marked.get(m_heap.nextCell)) { // Always false for the last cell in the block
238                 Cell* cell = &block->cells[m_heap.nextCell];
239
240                 m_heap.operationInProgress = Allocation;
241                 JSCell* imp = reinterpret_cast<JSCell*>(cell);
242                 imp->~JSCell();
243                 m_heap.operationInProgress = NoOperation;
244
245                 ++m_heap.nextCell;
246                 return cell;
247             }
248             block->marked.advanceToNextPossibleFreeCell(m_heap.nextCell);
249         } while (m_heap.nextCell != HeapConstants::cellsPerBlock);
250         m_heap.nextCell = 0;
251     } while (++m_heap.nextBlock != m_heap.usedBlocks);
252
253     // Slow case: reached the end of the heap. Mark live objects and start over.
254
255     reset();
256     goto allocate;
257 }
258
259 void Heap::resizeBlocks()
260 {
261     m_heap.didShrink = false;
262
263     size_t usedCellCount = markedCells();
264     size_t minCellCount = usedCellCount + max(ALLOCATIONS_PER_COLLECTION, usedCellCount);
265     size_t minBlockCount = (minCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
266
267     size_t maxCellCount = 1.25f * minCellCount;
268     size_t maxBlockCount = (maxCellCount + HeapConstants::cellsPerBlock - 1) / HeapConstants::cellsPerBlock;
269
270     if (m_heap.usedBlocks < minBlockCount)
271         growBlocks(minBlockCount);
272     else if (m_heap.usedBlocks > maxBlockCount)
273         shrinkBlocks(maxBlockCount);
274 }
275
276 void Heap::growBlocks(size_t neededBlocks)
277 {
278     ASSERT(m_heap.usedBlocks < neededBlocks);
279     while (m_heap.usedBlocks < neededBlocks)
280         allocateBlock();
281 }
282
283 void Heap::shrinkBlocks(size_t neededBlocks)
284 {
285     ASSERT(m_heap.usedBlocks > neededBlocks);
286     
287     // Clear the always-on last bit, so isEmpty() isn't fooled by it.
288     for (size_t i = 0; i < m_heap.usedBlocks; ++i)
289         m_heap.collectorBlock(i)->marked.clear(HeapConstants::cellsPerBlock - 1);
290
291     for (size_t i = 0; i != m_heap.usedBlocks && m_heap.usedBlocks != neededBlocks; ) {
292         if (m_heap.collectorBlock(i)->marked.isEmpty()) {
293             freeBlock(i);
294         } else
295             ++i;
296     }
297
298     // Reset the always-on last bit.
299     for (size_t i = 0; i < m_heap.usedBlocks; ++i)
300         m_heap.collectorBlock(i)->marked.set(HeapConstants::cellsPerBlock - 1);
301 }
302
303 inline bool isPointerAligned(void* p)
304 {
305     return (((intptr_t)(p) & (sizeof(char*) - 1)) == 0);
306 }
307
308 // Cell size needs to be a power of two for isPossibleCell to be valid.
309 COMPILE_ASSERT(sizeof(CollectorCell) % 2 == 0, Collector_cell_size_is_power_of_two);
310
311 static inline bool isCellAligned(void *p)
312 {
313     return (((intptr_t)(p) & CELL_MASK) == 0);
314 }
315
316 static inline bool isPossibleCell(void* p)
317 {
318     return isCellAligned(p) && p;
319 }
320
321 void Heap::markConservatively(MarkStack& markStack, void* start, void* end)
322 {
323 #if OS(WINCE)
324     if (start > end) {
325         void* tmp = start;
326         start = end;
327         end = tmp;
328     }
329 #else
330     ASSERT(start <= end);
331 #endif
332
333     ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000);
334     ASSERT(isPointerAligned(start));
335     ASSERT(isPointerAligned(end));
336
337     char** p = static_cast<char**>(start);
338     char** e = static_cast<char**>(end);
339
340     while (p != e) {
341         char* x = *p++;
342         if (isPossibleCell(x)) {
343             size_t usedBlocks;
344             uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x);
345             xAsBits &= CELL_ALIGN_MASK;
346
347             uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK;
348             const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
349             if (offset > lastCellOffset)
350                 continue;
351
352             CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset);
353             usedBlocks = m_heap.usedBlocks;
354             for (size_t block = 0; block < usedBlocks; block++) {
355                 if (m_heap.collectorBlock(block) != blockAddr)
356                     continue;
357                 markStack.append(reinterpret_cast<JSCell*>(xAsBits));
358             }
359         }
360     }
361 }
362
363 void Heap::updateWeakGCHandles()
364 {
365     for (unsigned i = 0; i < m_weakGCHandlePools.size(); ++i)
366         weakGCHandlePool(i)->update();
367 }
368
369 void WeakGCHandlePool::update()
370 {
371     for (unsigned i = 1; i < WeakGCHandlePool::numPoolEntries; ++i) {
372         if (m_entries[i].isValidPtr()) {
373             JSCell* cell = m_entries[i].get();
374             if (!cell || !Heap::isCellMarked(cell))
375                 m_entries[i].invalidate();
376         }
377     }
378 }
379
380 WeakGCHandle* Heap::addWeakGCHandle(JSCell* ptr)
381 {
382     for (unsigned i = 0; i < m_weakGCHandlePools.size(); ++i)
383         if (!weakGCHandlePool(i)->isFull())
384             return weakGCHandlePool(i)->allocate(ptr);
385
386     PageAllocationAligned allocation = PageAllocationAligned::allocate(WeakGCHandlePool::poolSize, WeakGCHandlePool::poolSize, OSAllocator::JSGCHeapPages);
387     m_weakGCHandlePools.append(allocation);
388
389     WeakGCHandlePool* pool = new (allocation.base()) WeakGCHandlePool();
390     return pool->allocate(ptr);
391 }
392
393 void Heap::protect(JSValue k)
394 {
395     ASSERT(k);
396     ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
397
398     if (!k.isCell())
399         return;
400
401     m_protectedValues.add(k.asCell());
402 }
403
404 bool Heap::unprotect(JSValue k)
405 {
406     ASSERT(k);
407     ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());
408
409     if (!k.isCell())
410         return false;
411
412     return m_protectedValues.remove(k.asCell());
413 }
414
415 void Heap::markProtectedObjects(MarkStack& markStack)
416 {
417     ProtectCountSet::iterator end = m_protectedValues.end();
418     for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) {
419         markStack.append(it->first);
420         markStack.drain();
421     }
422 }
423
424 void Heap::pushTempSortVector(Vector<ValueStringPair>* tempVector)
425 {
426     m_tempSortingVectors.append(tempVector);
427 }
428
429 void Heap::popTempSortVector(Vector<ValueStringPair>* tempVector)
430 {
431     ASSERT_UNUSED(tempVector, tempVector == m_tempSortingVectors.last());
432     m_tempSortingVectors.removeLast();
433 }
434     
435 void Heap::markTempSortVectors(MarkStack& markStack)
436 {
437     typedef Vector<Vector<ValueStringPair>* > VectorOfValueStringVectors;
438
439     VectorOfValueStringVectors::iterator end = m_tempSortingVectors.end();
440     for (VectorOfValueStringVectors::iterator it = m_tempSortingVectors.begin(); it != end; ++it) {
441         Vector<ValueStringPair>* tempSortingVector = *it;
442
443         Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end();
444         for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt)
445             if (vectorIt->first)
446                 markStack.append(vectorIt->first);
447         markStack.drain();
448     }
449 }
450     
451 void Heap::clearMarkBits()
452 {
453     for (size_t i = 0; i < m_heap.usedBlocks; ++i)
454         clearMarkBits(m_heap.collectorBlock(i));
455 }
456
457 void Heap::clearMarkBits(CollectorBlock* block)
458 {
459     // allocate assumes that the last cell in every block is marked.
460     block->marked.clearAll();
461     block->marked.set(HeapConstants::cellsPerBlock - 1);
462 }
463
464 size_t Heap::markedCells(size_t startBlock, size_t startCell) const
465 {
466     ASSERT(startBlock <= m_heap.usedBlocks);
467     ASSERT(startCell < HeapConstants::cellsPerBlock);
468
469     if (startBlock >= m_heap.usedBlocks)
470         return 0;
471
472     size_t result = 0;
473     result += m_heap.collectorBlock(startBlock)->marked.count(startCell);
474     for (size_t i = startBlock + 1; i < m_heap.usedBlocks; ++i)
475         result += m_heap.collectorBlock(i)->marked.count();
476
477     return result;
478 }
479
480 void Heap::sweep()
481 {
482     ASSERT(m_heap.operationInProgress == NoOperation);
483     if (m_heap.operationInProgress != NoOperation)
484         CRASH();
485     m_heap.operationInProgress = Collection;
486     
487 #if !ENABLE(JSC_ZOMBIES)
488     Structure* dummyMarkableCellStructure = m_globalData->dummyMarkableCellStructure.get();
489 #endif
490
491     DeadObjectIterator it(m_heap, m_heap.nextBlock, m_heap.nextCell);
492     DeadObjectIterator end(m_heap, m_heap.usedBlocks);
493     for ( ; it != end; ++it) {
494         JSCell* cell = *it;
495 #if ENABLE(JSC_ZOMBIES)
496         if (!cell->isZombie()) {
497             const ClassInfo* info = cell->classInfo();
498             cell->~JSCell();
499             new (cell) JSZombie(info, JSZombie::leakedZombieStructure());
500             Heap::markCell(cell);
501         }
502 #else
503         cell->~JSCell();
504         // Callers of sweep assume it's safe to mark any cell in the heap.
505         new (cell) JSCell(dummyMarkableCellStructure);
506 #endif
507     }
508
509     m_heap.operationInProgress = NoOperation;
510 }
511
512 void Heap::markRoots()
513 {
514 #ifndef NDEBUG
515     if (m_globalData->isSharedInstance()) {
516         ASSERT(JSLock::lockCount() > 0);
517         ASSERT(JSLock::currentThreadIsHoldingLock());
518     }
519 #endif
520
521     ASSERT(m_heap.operationInProgress == NoOperation);
522     if (m_heap.operationInProgress != NoOperation)
523         CRASH();
524
525     m_heap.operationInProgress = Collection;
526
527     MarkStack& markStack = m_globalData->markStack;
528
529     // Reset mark bits.
530     clearMarkBits();
531
532     // Mark stack roots.
533     m_machineStackMarker.markMachineStackConservatively(markStack);
534     m_globalData->interpreter->registerFile().markCallFrames(markStack, this);
535
536     // Mark explicitly registered roots.
537     markProtectedObjects(markStack);
538     
539     // Mark temporary vector for Array sorting
540     markTempSortVectors(markStack);
541
542     // Mark misc. other roots.
543     if (m_markListSet && m_markListSet->size())
544         MarkedArgumentBuffer::markLists(markStack, *m_markListSet);
545     if (m_globalData->exception)
546         markStack.append(m_globalData->exception);
547     if (m_globalData->firstStringifierToMark)
548         JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark);
549
550     // Mark the small strings cache last, since it will clear itself if nothing
551     // else has marked it.
552     m_globalData->smallStrings.markChildren(markStack);
553
554     markStack.drain();
555     markStack.compact();
556
557     updateWeakGCHandles();
558
559     m_heap.operationInProgress = NoOperation;
560 }
561
562 size_t Heap::objectCount() const
563 {
564     return m_heap.nextBlock * HeapConstants::cellsPerBlock // allocated full blocks
565            + m_heap.nextCell // allocated cells in current block
566            + markedCells(m_heap.nextBlock, m_heap.nextCell) // marked cells in remainder of m_heap
567            - m_heap.usedBlocks; // 1 cell per block is a dummy sentinel
568 }
569
570 void Heap::addToStatistics(Heap::Statistics& statistics) const
571 {
572     statistics.size += m_heap.usedBlocks * BLOCK_SIZE;
573     statistics.free += m_heap.usedBlocks * BLOCK_SIZE - (objectCount() * HeapConstants::cellSize);
574 }
575
576 Heap::Statistics Heap::statistics() const
577 {
578     Statistics statistics = { 0, 0 };
579     addToStatistics(statistics);
580     return statistics;
581 }
582
583 size_t Heap::size() const
584 {
585     return m_heap.usedBlocks * BLOCK_SIZE;
586 }
587
588 size_t Heap::globalObjectCount()
589 {
590     size_t count = 0;
591     if (JSGlobalObject* head = m_globalData->head) {
592         JSGlobalObject* o = head;
593         do {
594             ++count;
595             o = o->next();
596         } while (o != head);
597     }
598     return count;
599 }
600
601 size_t Heap::protectedGlobalObjectCount()
602 {
603     size_t count = 0;
604     if (JSGlobalObject* head = m_globalData->head) {
605         JSGlobalObject* o = head;
606         do {
607             if (m_protectedValues.contains(o))
608                 ++count;
609             o = o->next();
610         } while (o != head);
611     }
612
613     return count;
614 }
615
616 size_t Heap::protectedObjectCount()
617 {
618     return m_protectedValues.size();
619 }
620
621 static const char* typeName(JSCell* cell)
622 {
623     if (cell->isString())
624         return "string";
625     if (cell->isGetterSetter())
626         return "Getter-Setter";
627     if (cell->isAPIValueWrapper())
628         return "API wrapper";
629     if (cell->isPropertyNameIterator())
630         return "For-in iterator";
631     if (!cell->isObject())
632         return "[empty cell]";
633     const ClassInfo* info = cell->classInfo();
634     return info ? info->className : "Object";
635 }
636
637 HashCountedSet<const char*>* Heap::protectedObjectTypeCounts()
638 {
639     HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
640
641     ProtectCountSet::iterator end = m_protectedValues.end();
642     for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
643         counts->add(typeName(it->first));
644
645     return counts;
646 }
647
648 HashCountedSet<const char*>* Heap::objectTypeCounts()
649 {
650     HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
651
652     LiveObjectIterator it = primaryHeapBegin();
653     LiveObjectIterator heapEnd = primaryHeapEnd();
654     for ( ; it != heapEnd; ++it)
655         counts->add(typeName(*it));
656
657     return counts;
658 }
659
660 bool Heap::isBusy()
661 {
662     return m_heap.operationInProgress != NoOperation;
663 }
664
665 void Heap::reset()
666 {
667     ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
668     JAVASCRIPTCORE_GC_BEGIN();
669
670     markRoots();
671
672     JAVASCRIPTCORE_GC_MARKED();
673
674     m_heap.nextCell = 0;
675     m_heap.nextBlock = 0;
676     m_heap.extraCost = 0;
677 #if ENABLE(JSC_ZOMBIES)
678     sweep();
679 #endif
680     resizeBlocks();
681
682     JAVASCRIPTCORE_GC_END();
683
684     (*m_activityCallback)();
685 }
686
687 void Heap::collectAllGarbage()
688 {
689     ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable());
690     JAVASCRIPTCORE_GC_BEGIN();
691
692     // If the last iteration through the heap deallocated blocks, we need
693     // to clean up remaining garbage before marking. Otherwise, the conservative
694     // marking mechanism might follow a pointer to unmapped memory.
695     if (m_heap.didShrink)
696         sweep();
697
698     markRoots();
699
700     JAVASCRIPTCORE_GC_MARKED();
701
702     m_heap.nextCell = 0;
703     m_heap.nextBlock = 0;
704     m_heap.extraCost = 0;
705     sweep();
706     resizeBlocks();
707
708     JAVASCRIPTCORE_GC_END();
709 }
710
711 LiveObjectIterator Heap::primaryHeapBegin()
712 {
713     return LiveObjectIterator(m_heap, 0);
714 }
715
716 LiveObjectIterator Heap::primaryHeapEnd()
717 {
718     return LiveObjectIterator(m_heap, m_heap.usedBlocks);
719 }
720
721 void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback)
722 {
723     m_activityCallback = activityCallback;
724 }
725
726 GCActivityCallback* Heap::activityCallback()
727 {
728     return m_activityCallback.get();
729 }
730
731 } // namespace JSC