8ede87927e867443187139231fd3c92d1524163b
[WebKit-https.git] / 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(const PageAllocationAligned& allocation, Heap* heap, size_t cellSize, bool cellsNeedDestruction, bool onlyContainsStructures)
36 {
37     return new (NotNull, allocation.base()) MarkedBlock(allocation, heap, cellSize, cellsNeedDestruction, onlyContainsStructures);
38 }
39
40 PageAllocationAligned MarkedBlock::destroy(MarkedBlock* block)
41 {
42     PageAllocationAligned allocation;
43     swap(allocation, block->m_allocation);
44
45     block->~MarkedBlock();
46     return allocation;
47 }
48
49 MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, Heap* heap, size_t cellSize, bool cellsNeedDestruction, bool onlyContainsStructures)
50     : HeapBlock(allocation)
51     , m_atomsPerCell((cellSize + atomSize - 1) / atomSize)
52     , m_endAtom(atomsPerBlock - m_atomsPerCell + 1)
53     , m_cellsNeedDestruction(cellsNeedDestruction)
54     , m_onlyContainsStructures(onlyContainsStructures)
55     , m_state(New) // All cells start out unmarked.
56     , m_weakSet(heap)
57 {
58     ASSERT(heap);
59     HEAP_LOG_BLOCK_STATE_TRANSITION(this);
60 }
61
62 inline void MarkedBlock::callDestructor(JSCell* cell)
63 {
64     // A previous eager sweep may already have run cell's destructor.
65     if (cell->isZapped())
66         return;
67
68 #if ENABLE(SIMPLE_HEAP_PROFILING)
69     m_heap->m_destroyedTypeCounts.countVPtr(vptr);
70 #endif
71
72 #if !ASSERT_DISABLED || ENABLE(GC_VALIDATION)
73     cell->clearStructure();
74 #endif
75
76     cell->methodTable()->destroy(cell);
77     cell->zap();
78 }
79
80 template<MarkedBlock::BlockState blockState, MarkedBlock::SweepMode sweepMode, bool destructorCallNeeded>
81 MarkedBlock::FreeList MarkedBlock::specializedSweep()
82 {
83     ASSERT(blockState != Allocated && blockState != FreeListed);
84     ASSERT(destructorCallNeeded || sweepMode != SweepOnly);
85
86     // This produces a free list that is ordered in reverse through the block.
87     // This is fine, since the allocation code makes no assumptions about the
88     // order of the free list.
89     FreeCell* head = 0;
90     size_t count = 0;
91     for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) {
92         if (blockState == Marked && m_marks.get(i))
93             continue;
94
95         JSCell* cell = reinterpret_cast_ptr<JSCell*>(&atoms()[i]);
96         if (blockState == Zapped && !cell->isZapped())
97             continue;
98
99         if (destructorCallNeeded && blockState != New)
100             callDestructor(cell);
101
102         if (sweepMode == SweepToFreeList) {
103             FreeCell* freeCell = reinterpret_cast<FreeCell*>(cell);
104             freeCell->next = head;
105             head = freeCell;
106             ++count;
107         }
108     }
109
110     m_state = ((sweepMode == SweepToFreeList) ? FreeListed : Zapped);
111     return FreeList(head, count * cellSize());
112 }
113
114 MarkedBlock::FreeList MarkedBlock::sweep(SweepMode sweepMode)
115 {
116     HEAP_LOG_BLOCK_STATE_TRANSITION(this);
117
118     m_weakSet.sweep();
119
120     if (sweepMode == SweepOnly && !m_cellsNeedDestruction)
121         return FreeList();
122
123     if (m_cellsNeedDestruction)
124         return sweepHelper<true>(sweepMode);
125     return sweepHelper<false>(sweepMode);
126 }
127
128 template<bool destructorCallNeeded>
129 MarkedBlock::FreeList MarkedBlock::sweepHelper(SweepMode sweepMode)
130 {
131     switch (m_state) {
132     case New:
133         ASSERT(sweepMode == SweepToFreeList);
134         return specializedSweep<New, SweepToFreeList, destructorCallNeeded>();
135     case FreeListed:
136         // Happens when a block transitions to fully allocated.
137         ASSERT(sweepMode == SweepToFreeList);
138         return FreeList();
139     case Allocated:
140         ASSERT_NOT_REACHED();
141         return FreeList();
142     case Marked:
143         return sweepMode == SweepToFreeList
144             ? specializedSweep<Marked, SweepToFreeList, destructorCallNeeded>()
145             : specializedSweep<Marked, SweepOnly, destructorCallNeeded>();
146     case Zapped:
147         return sweepMode == SweepToFreeList
148             ? specializedSweep<Zapped, SweepToFreeList, destructorCallNeeded>()
149             : specializedSweep<Zapped, SweepOnly, destructorCallNeeded>();
150     }
151
152     ASSERT_NOT_REACHED();
153     return FreeList();
154 }
155
156 void MarkedBlock::zapFreeList(const FreeList& freeList)
157 {
158     HEAP_LOG_BLOCK_STATE_TRANSITION(this);
159     FreeCell* head = freeList.head;
160
161     if (m_state == Marked) {
162         // If the block is in the Marked state then we know that:
163         // 1) It was not used for allocation during the previous allocation cycle.
164         // 2) It may have dead objects, and we only know them to be dead by the
165         //    fact that their mark bits are unset.
166         // Hence if the block is Marked we need to leave it Marked.
167         
168         ASSERT(!head);
169         
170         return;
171     }
172     
173     if (m_state == Zapped) {
174         // If the block is in the Zapped state then we know that someone already
175         // zapped it for us. This could not have happened during a GC, but might
176         // be the result of someone having done a GC scan to perform some operation
177         // over all live objects (or all live blocks). It also means that somebody
178         // had allocated in this block since the last GC, swept all dead objects
179         // onto the free list, left the block in the FreeListed state, then the heap
180         // scan happened, and canonicalized the block, leading to all dead objects
181         // being zapped. Therefore, it is safe for us to simply do nothing, since
182         // dead objects will have 0 in their vtables and live objects will have
183         // non-zero vtables, which is consistent with the block being zapped.
184         
185         ASSERT(!head);
186         
187         return;
188     }
189     
190     ASSERT(m_state == FreeListed);
191     
192     // Roll back to a coherent state for Heap introspection. Cells newly
193     // allocated from our free list are not currently marked, so we need another
194     // way to tell what's live vs dead. We use zapping for that.
195     
196     FreeCell* next;
197     for (FreeCell* current = head; current; current = next) {
198         next = current->next;
199         reinterpret_cast<JSCell*>(current)->zap();
200     }
201     
202     m_state = Zapped;
203 }
204
205 } // namespace JSC