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