6496ab531a439f039283e1b8d9a4a3e933ce4cd5
[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(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 MarkedBlock* MarkedBlock::recycle(MarkedBlock* block, size_t cellSize)
44 {
45     return new (block) MarkedBlock(block->m_allocation, block->m_heap, cellSize);
46 }
47
48 void MarkedBlock::destroy(MarkedBlock* block)
49 {
50     block->m_allocation.deallocate();
51 }
52
53 MarkedBlock::MarkedBlock(const PageAllocationAligned& allocation, Heap* heap, size_t cellSize)
54     : m_atomsPerCell((cellSize + atomSize - 1) / atomSize)
55     , m_endAtom(atomsPerBlock - m_atomsPerCell + 1)
56     , m_state(New) // All cells start out unmarked.
57     , m_allocation(allocation)
58     , m_heap(heap)
59 {
60     HEAP_LOG_BLOCK_STATE_TRANSITION(this);
61 }
62
63 inline void MarkedBlock::callDestructor(JSCell* cell, void* jsFinalObjectVPtr)
64 {
65     // A previous eager sweep may already have run cell's destructor.
66     if (cell->isZapped())
67         return;
68
69     void* vptr = cell->vptr();
70 #if ENABLE(SIMPLE_HEAP_PROFILING)
71     m_heap->m_destroyedTypeCounts.countVPtr(vptr);
72 #endif
73     if (vptr == jsFinalObjectVPtr)
74         reinterpret_cast<JSFinalObject*>(cell)->JSFinalObject::~JSFinalObject();
75     else
76         cell->~JSCell();
77
78     cell->zap();
79 }
80
81 template<MarkedBlock::BlockState blockState, MarkedBlock::SweepMode sweepMode>
82 MarkedBlock::FreeCell* MarkedBlock::specializedSweep()
83 {
84     ASSERT(blockState != Allocated && blockState != FreeListed);
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     void* jsFinalObjectVPtr = m_heap->globalData()->jsFinalObjectVPtr;
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<JSCell*>(&atoms()[i]);
96         if (blockState == Zapped && !cell->isZapped())
97             continue;
98
99         if (blockState != New)
100             callDestructor(cell, jsFinalObjectVPtr);
101
102         if (sweepMode == SweepToFreeList) {
103             FreeCell* freeCell = reinterpret_cast<FreeCell*>(cell);
104             freeCell->next = head;
105             head = freeCell;
106         }
107     }
108
109     m_state = ((sweepMode == SweepToFreeList) ? FreeListed : Zapped);
110     return head;
111 }
112
113 MarkedBlock::FreeCell* MarkedBlock::sweep(SweepMode sweepMode)
114 {
115     HEAP_LOG_BLOCK_STATE_TRANSITION(this);
116
117     switch (m_state) {
118     case New:
119         ASSERT(sweepMode == SweepToFreeList);
120         return specializedSweep<New, SweepToFreeList>();
121     case FreeListed:
122         // Happens when a block transitions to fully allocated.
123         ASSERT(sweepMode == SweepToFreeList);
124         return 0;
125     case Allocated:
126         ASSERT_NOT_REACHED();
127         return 0;
128     case Marked:
129         return sweepMode == SweepToFreeList
130             ? specializedSweep<Marked, SweepToFreeList>()
131             : specializedSweep<Marked, SweepOnly>();
132     case Zapped:
133         return sweepMode == SweepToFreeList
134             ? specializedSweep<Zapped, SweepToFreeList>()
135             : specializedSweep<Zapped, SweepOnly>();
136     }
137
138     ASSERT_NOT_REACHED();
139     return 0;
140 }
141
142 void MarkedBlock::zapFreeList(FreeCell* firstFreeCell)
143 {
144     HEAP_LOG_BLOCK_STATE_TRANSITION(this);
145
146     // Roll back to a coherent state for Heap introspection. Cells newly
147     // allocated from our free list are not currently marked, so we need another
148     // way to tell what's live vs dead. We use zapping for that.
149
150     FreeCell* next;
151     for (FreeCell* current = firstFreeCell; current; current = next) {
152         next = current->next;
153         reinterpret_cast<JSCell*>(current)->zap();
154     }
155
156     m_state = Zapped;
157 }
158
159 } // namespace JSC