initial import
[vuplus_webkit] / Source / JavaScriptCore / heap / MarkedBlock.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "MarkedBlock.h"
28
29 #include "JSCell.h"
30 #include "JSObject.h"
31 #include "ScopeChain.h"
32
33 namespace JSC {
34
35 MarkedBlock* MarkedBlock::create(Heap* heap, size_t cellSize)
36 {
37     PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, blockSize, OSAllocator::JSGCHeapPages);
38     if (!static_cast<bool>(allocation))
39         CRASH();
40     return new (allocation.base()) MarkedBlock(allocation, heap, cellSize);
41 }
42
43 void MarkedBlock::destroy(MarkedBlock* block)
44 {
45     block->m_allocation.deallocate();
46 }
47
48 MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, Heap* heap, size_t cellSize)
49     : m_inNewSpace(false)
50     , m_allocation(allocation)
51     , m_heap(heap)
52 {
53     initForCellSize(cellSize);
54 }
55
56 void MarkedBlock::initForCellSize(size_t cellSize)
57 {
58     m_atomsPerCell = (cellSize + atomSize - 1) / atomSize;
59     m_endAtom = atomsPerBlock - m_atomsPerCell + 1;
60     setDestructorState(SomeFreeCellsStillHaveObjects);
61 }
62
63 template<MarkedBlock::DestructorState specializedDestructorState>
64 void MarkedBlock::callDestructor(JSCell* cell, void* jsFinalObjectVPtr)
65 {
66     if (specializedDestructorState == FreeCellsDontHaveObjects)
67         return;
68     void* vptr = cell->vptr();
69     if (specializedDestructorState == AllFreeCellsHaveObjects || vptr) {
70 #if ENABLE(SIMPLE_HEAP_PROFILING)
71         m_heap->m_destroyedTypeCounts.countVPtr(vptr);
72 #endif
73         if (vptr == jsFinalObjectVPtr) {
74             JSFinalObject* object = reinterpret_cast<JSFinalObject*>(cell);
75             object->JSFinalObject::~JSFinalObject();
76         } else
77             cell->~JSCell();
78     }
79 }
80
81 template<MarkedBlock::DestructorState specializedDestructorState>
82 void MarkedBlock::specializedReset()
83 {
84     void* jsFinalObjectVPtr = m_heap->globalData()->jsFinalObjectVPtr;
85
86     for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell)
87         callDestructor<specializedDestructorState>(reinterpret_cast<JSCell*>(&atoms()[i]), jsFinalObjectVPtr);
88 }
89
90 void MarkedBlock::reset()
91 {
92     switch (destructorState()) {
93     case FreeCellsDontHaveObjects:
94     case SomeFreeCellsStillHaveObjects:
95         specializedReset<SomeFreeCellsStillHaveObjects>();
96         break;
97     default:
98         ASSERT(destructorState() == AllFreeCellsHaveObjects);
99         specializedReset<AllFreeCellsHaveObjects>();
100         break;
101     }
102 }
103
104 template<MarkedBlock::DestructorState specializedDestructorState>
105 void MarkedBlock::specializedSweep()
106 {
107     if (specializedDestructorState != FreeCellsDontHaveObjects) {
108         void* jsFinalObjectVPtr = m_heap->globalData()->jsFinalObjectVPtr;
109         
110         for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) {
111             if (m_marks.get(i))
112                 continue;
113             
114             JSCell* cell = reinterpret_cast<JSCell*>(&atoms()[i]);
115             callDestructor<specializedDestructorState>(cell, jsFinalObjectVPtr);
116             cell->setVPtr(0);
117         }
118         
119         setDestructorState(FreeCellsDontHaveObjects);
120     }
121 }
122
123 void MarkedBlock::sweep()
124 {
125     HEAP_DEBUG_BLOCK(this);
126     
127     switch (destructorState()) {
128     case FreeCellsDontHaveObjects:
129         break;
130     case SomeFreeCellsStillHaveObjects:
131         specializedSweep<SomeFreeCellsStillHaveObjects>();
132         break;
133     default:
134         ASSERT(destructorState() == AllFreeCellsHaveObjects);
135         specializedSweep<AllFreeCellsHaveObjects>();
136         break;
137     }
138 }
139
140 template<MarkedBlock::DestructorState specializedDestructorState>
141 ALWAYS_INLINE MarkedBlock::FreeCell* MarkedBlock::produceFreeList()
142 {
143     // This returns a free list that is ordered in reverse through the block.
144     // This is fine, since the allocation code makes no assumptions about the
145     // order of the free list.
146     
147     void* jsFinalObjectVPtr = m_heap->globalData()->jsFinalObjectVPtr;
148     
149     FreeCell* result = 0;
150     
151     for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) {
152         if (!m_marks.testAndSet(i)) {
153             JSCell* cell = reinterpret_cast<JSCell*>(&atoms()[i]);
154             if (specializedDestructorState != FreeCellsDontHaveObjects)
155                 callDestructor<specializedDestructorState>(cell, jsFinalObjectVPtr);
156             FreeCell* freeCell = reinterpret_cast<FreeCell*>(cell);
157             freeCell->next = result;
158             result = freeCell;
159         }
160     }
161     
162     // This is sneaky: if we're producing a free list then we intend to
163     // fill up the free cells in the block with objects, which means that
164     // if we have a new GC then all of the free stuff in this block will
165     // comprise objects rather than empty cells.
166     setDestructorState(AllFreeCellsHaveObjects);
167
168     return result;
169 }
170
171 MarkedBlock::FreeCell* MarkedBlock::lazySweep()
172 {
173     // This returns a free list that is ordered in reverse through the block.
174     // This is fine, since the allocation code makes no assumptions about the
175     // order of the free list.
176     
177     HEAP_DEBUG_BLOCK(this);
178     
179     switch (destructorState()) {
180     case FreeCellsDontHaveObjects:
181         return produceFreeList<FreeCellsDontHaveObjects>();
182     case SomeFreeCellsStillHaveObjects:
183         return produceFreeList<SomeFreeCellsStillHaveObjects>();
184     default:
185         ASSERT(destructorState() == AllFreeCellsHaveObjects);
186         return produceFreeList<AllFreeCellsHaveObjects>();
187     }
188 }
189
190 MarkedBlock::FreeCell* MarkedBlock::blessNewBlockForFastPath()
191 {
192     // This returns a free list that is ordered in reverse through the block,
193     // as in lazySweep() above.
194     
195     HEAP_DEBUG_BLOCK(this);
196
197     FreeCell* result = 0;
198     for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) {
199         m_marks.set(i);
200         FreeCell* freeCell = reinterpret_cast<FreeCell*>(&atoms()[i]);
201         freeCell->next = result;
202         result = freeCell;
203     }
204     
205     // See produceFreeList(). If we're here then we intend to fill the
206     // block with objects, so once a GC happens, all free cells will be
207     // occupied by objects.
208     setDestructorState(AllFreeCellsHaveObjects);
209
210     return result;
211 }
212
213 void MarkedBlock::blessNewBlockForSlowPath()
214 {
215     HEAP_DEBUG_BLOCK(this);
216
217     m_marks.clearAll();
218     for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell)
219         reinterpret_cast<FreeCell*>(&atoms()[i])->setNoObject();
220     
221     setDestructorState(FreeCellsDontHaveObjects);
222 }
223
224 void MarkedBlock::canonicalizeBlock(FreeCell* firstFreeCell)
225 {
226     HEAP_DEBUG_BLOCK(this);
227     
228     ASSERT(destructorState() == AllFreeCellsHaveObjects);
229     
230     if (firstFreeCell) {
231         for (FreeCell* current = firstFreeCell; current;) {
232             FreeCell* next = current->next;
233             size_t i = atomNumber(current);
234             
235             m_marks.clear(i);
236             
237             current->setNoObject();
238             
239             current = next;
240         }
241         
242         setDestructorState(SomeFreeCellsStillHaveObjects);
243     }
244 }
245
246 } // namespace JSC