c3cb4f2d72a84dfd655dcc98be54a765ee5889e5
[WebKit-https.git] / Source / JavaScriptCore / runtime / MarkStack.h
1 /*
2  * Copyright (C) 2009 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 #ifndef MarkStack_h
27 #define MarkStack_h
28
29 #include "JSValue.h"
30 #include <wtf/Vector.h>
31 #include <wtf/Noncopyable.h>
32 #include <wtf/OSAllocator.h>
33
34 namespace JSC {
35
36     class JSGlobalData;
37     class Register;
38     
39     enum MarkSetProperties { MayContainNullValues, NoNullValues };
40     
41     class MarkStack {
42         WTF_MAKE_NONCOPYABLE(MarkStack);
43     public:
44         MarkStack(void* jsArrayVPtr)
45             : m_jsArrayVPtr(jsArrayVPtr)
46 #if !ASSERT_DISABLED
47             , m_isCheckingForDefaultMarkViolation(false)
48             , m_isDraining(false)
49 #endif
50         {
51         }
52
53         ALWAYS_INLINE void append(JSValue);
54         void append(JSCell*);
55         
56         ALWAYS_INLINE void appendValues(Register* values, size_t count, MarkSetProperties properties = NoNullValues)
57         {
58             appendValues(reinterpret_cast<JSValue*>(values), count, properties);
59         }
60
61         ALWAYS_INLINE void appendValues(JSValue* values, size_t count, MarkSetProperties properties = NoNullValues)
62         {
63             if (count)
64                 m_markSets.append(MarkSet(values, values + count, properties));
65         }
66
67         inline void drain();
68         void compact();
69
70         ~MarkStack()
71         {
72             ASSERT(m_markSets.isEmpty());
73             ASSERT(m_values.isEmpty());
74         }
75
76     private:
77         void markChildren(JSCell*);
78
79         struct MarkSet {
80             MarkSet(JSValue* values, JSValue* end, MarkSetProperties properties)
81                 : m_values(values)
82                 , m_end(end)
83                 , m_properties(properties)
84             {
85                 ASSERT(values);
86             }
87             JSValue* m_values;
88             JSValue* m_end;
89             MarkSetProperties m_properties;
90         };
91
92         static void* allocateStack(size_t size) { return OSAllocator::reserveAndCommit(size); }
93         static void releaseStack(void* addr, size_t size) { OSAllocator::decommitAndRelease(addr, size); }
94
95         static void initializePagesize();
96         static size_t pageSize()
97         {
98             if (!s_pageSize)
99                 initializePagesize();
100             return s_pageSize;
101         }
102
103         template <typename T> struct MarkStackArray {
104             MarkStackArray()
105                 : m_top(0)
106                 , m_allocated(MarkStack::pageSize())
107                 , m_capacity(m_allocated / sizeof(T))
108             {
109                 m_data = reinterpret_cast<T*>(allocateStack(m_allocated));
110             }
111
112             ~MarkStackArray()
113             {
114                 releaseStack(m_data, m_allocated);
115             }
116
117             void expand()
118             {
119                 size_t oldAllocation = m_allocated;
120                 m_allocated *= 2;
121                 m_capacity = m_allocated / sizeof(T);
122                 void* newData = allocateStack(m_allocated);
123                 memcpy(newData, m_data, oldAllocation);
124                 releaseStack(m_data, oldAllocation);
125                 m_data = reinterpret_cast<T*>(newData);
126             }
127
128             inline void append(const T& v)
129             {
130                 if (m_top == m_capacity)
131                     expand();
132                 m_data[m_top++] = v;
133             }
134
135             inline T removeLast()
136             {
137                 ASSERT(m_top);
138                 return m_data[--m_top];
139             }
140             
141             inline T& last()
142             {
143                 ASSERT(m_top);
144                 return m_data[m_top - 1];
145             }
146
147             inline bool isEmpty()
148             {
149                 return m_top == 0;
150             }
151
152             inline size_t size() { return m_top; }
153
154             inline void shrinkAllocation(size_t size)
155             {
156                 ASSERT(size <= m_allocated);
157                 ASSERT(0 == (size % MarkStack::pageSize()));
158                 if (size == m_allocated)
159                     return;
160 #if OS(WINDOWS) || OS(SYMBIAN) || PLATFORM(BREWMP)
161                 // We cannot release a part of a region with VirtualFree.  To get around this,
162                 // we'll release the entire region and reallocate the size that we want.
163                 releaseStack(m_data, m_allocated);
164                 m_data = reinterpret_cast<T*>(allocateStack(size));
165 #else
166                 releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size);
167 #endif
168                 m_allocated = size;
169                 m_capacity = m_allocated / sizeof(T);
170             }
171
172         private:
173             size_t m_top;
174             size_t m_allocated;
175             size_t m_capacity;
176             T* m_data;
177         };
178
179         void* m_jsArrayVPtr;
180         MarkStackArray<MarkSet> m_markSets;
181         MarkStackArray<JSCell*> m_values;
182         static size_t s_pageSize;
183
184 #if !ASSERT_DISABLED
185     public:
186         bool m_isCheckingForDefaultMarkViolation;
187         bool m_isDraining;
188 #endif
189     };
190     
191 }
192
193 #endif