1/*
2 * Copyright (C) 2009, 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "MarkStack.h"
28
29#include "ConservativeRoots.h"
30#include "Heap.h"
31#include "JSArray.h"
32#include "JSCell.h"
33#include "JSObject.h"
34#include "ScopeChain.h"
35#include "Structure.h"
36
37namespace JSC {
38
39size_t MarkStack::s_pageSize = 0;
40
41void MarkStack::reset()
42{
43    ASSERT(s_pageSize);
44    m_values.shrinkAllocation(s_pageSize);
45    m_markSets.shrinkAllocation(s_pageSize);
46    m_opaqueRoots.clear();
47}
48
49void MarkStack::append(ConservativeRoots& conservativeRoots)
50{
51    JSCell** roots = conservativeRoots.roots();
52    size_t size = conservativeRoots.size();
53    for (size_t i = 0; i < size; ++i)
54        internalAppend(roots[i]);
55}
56
57inline void MarkStack::markChildren(JSCell* cell)
58{
59    ASSERT(Heap::isMarked(cell));
60    if (cell->structure()->typeInfo().type() < CompoundType) {
61        cell->JSCell::markChildren(*this);
62        return;
63    }
64
65    if (!cell->structure()->typeInfo().overridesMarkChildren()) {
66        ASSERT(cell->isObject());
67#ifdef NDEBUG
68        asObject(cell)->markChildrenDirect(*this);
69#else
70        ASSERT(!m_isCheckingForDefaultMarkViolation);
71        m_isCheckingForDefaultMarkViolation = true;
72        cell->markChildren(*this);
73        ASSERT(m_isCheckingForDefaultMarkViolation);
74        m_isCheckingForDefaultMarkViolation = false;
75#endif
76        return;
77    }
78    if (cell->vptr() == m_jsArrayVPtr) {
79        asArray(cell)->markChildrenDirect(*this);
80        return;
81    }
82    cell->markChildren(*this);
83}
84
85void MarkStack::drain()
86{
87#if !ASSERT_DISABLED
88    ASSERT(!m_isDraining);
89    m_isDraining = true;
90#endif
91    while (!m_markSets.isEmpty() || !m_values.isEmpty()) {
92        while (!m_markSets.isEmpty() && m_values.size() < 50) {
93            ASSERT(!m_markSets.isEmpty());
94            MarkSet& current = m_markSets.last();
95            ASSERT(current.m_values);
96            JSValue* end = current.m_end;
97            ASSERT(current.m_values);
98            ASSERT(current.m_values != end);
99        findNextUnmarkedNullValue:
100            ASSERT(current.m_values != end);
101            JSValue value = *current.m_values;
102            current.m_values++;
103
104            JSCell* cell;
105            if (!value || !value.isCell() || Heap::testAndSetMarked(cell = value.asCell())) {
106                if (current.m_values == end) {
107                    m_markSets.removeLast();
108                    continue;
109                }
110                goto findNextUnmarkedNullValue;
111            }
112
113            if (cell->structure()->typeInfo().type() < CompoundType) {
114                cell->JSCell::markChildren(*this);
115                if (current.m_values == end) {
116                    m_markSets.removeLast();
117                    continue;
118                }
119                goto findNextUnmarkedNullValue;
120            }
121
122            if (current.m_values == end)
123                m_markSets.removeLast();
124
125            markChildren(cell);
126        }
127        while (!m_values.isEmpty())
128            markChildren(m_values.removeLast());
129    }
130#if !ASSERT_DISABLED
131    m_isDraining = false;
132#endif
133}
134
135} // namespace JSC
136