initial import
[vuplus_webkit] / Source / JavaScriptCore / heap / MarkStack.h
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 #ifndef MarkStack_h
27 #define MarkStack_h
28
29 #include "HandleTypes.h"
30 #include "JSValue.h"
31 #include "Register.h"
32 #include "VTableSpectrum.h"
33 #include "WeakReferenceHarvester.h"
34 #include <wtf/HashMap.h>
35 #include <wtf/HashSet.h>
36 #include <wtf/Vector.h>
37 #include <wtf/Noncopyable.h>
38 #include <wtf/OSAllocator.h>
39 #include <wtf/PageBlock.h>
40
41 namespace JSC {
42
43     class ConservativeRoots;
44     class JSGlobalData;
45     class MarkStack;
46     class Register;
47     template<typename T> class WriteBarrierBase;
48     template<typename T> class JITWriteBarrier;
49     
50     struct MarkSet {
51         MarkSet(JSValue* values, JSValue* end);
52
53         JSValue* m_values;
54         JSValue* m_end;
55     };
56
57     template<typename T> class MarkStackArray {
58     public:
59         MarkStackArray();
60         ~MarkStackArray();
61
62         void expand();
63         void append(const T&);
64
65         T removeLast();
66         T& last();
67
68         bool isEmpty();
69         size_t size();
70
71         void shrinkAllocation(size_t);
72
73     private:
74         size_t m_top;
75         size_t m_allocated;
76         size_t m_capacity;
77         T* m_data;
78     };
79
80     class MarkStack {
81         WTF_MAKE_NONCOPYABLE(MarkStack);
82         friend class HeapRootVisitor; // Allowed to mark a JSValue* or JSCell** directly.
83
84     public:
85         static void* allocateStack(size_t);
86         static void releaseStack(void*, size_t);
87
88         MarkStack(void* jsArrayVPtr);
89         ~MarkStack();
90
91         void append(ConservativeRoots&);
92         
93         template<typename T> inline void append(JITWriteBarrier<T>*);
94         template<typename T> inline void append(WriteBarrierBase<T>*);
95         inline void appendValues(WriteBarrierBase<Unknown>*, size_t count);
96         
97         template<typename T>
98         inline void appendUnbarrieredPointer(T**);
99         
100         bool addOpaqueRoot(void*);
101         bool containsOpaqueRoot(void*);
102         int opaqueRootCount();
103
104         void reset();
105
106 #if ENABLE(SIMPLE_HEAP_PROFILING)
107         VTableSpectrum m_visitedTypeCounts;
108 #endif
109
110         void addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)
111         {
112             if (weakReferenceHarvester->m_nextAndFlag & 1)
113                 return;
114             weakReferenceHarvester->m_nextAndFlag = reinterpret_cast<uintptr_t>(m_firstWeakReferenceHarvester) | 1;
115             m_firstWeakReferenceHarvester = weakReferenceHarvester;
116         }
117
118     protected:
119 #if ENABLE(GC_VALIDATION)
120         static void validateSet(JSValue*, size_t);
121 #endif
122         static void validateValue(JSValue);
123
124         void append(JSValue*);
125         void append(JSValue*, size_t count);
126         void append(JSCell**);
127
128         void internalAppend(JSCell*);
129         void internalAppend(JSValue);
130
131         void* m_jsArrayVPtr;
132         MarkStackArray<MarkSet> m_markSets;
133         MarkStackArray<JSCell*> m_values;
134         HashSet<void*> m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector.
135         WeakReferenceHarvester* m_firstWeakReferenceHarvester;
136         
137 #if !ASSERT_DISABLED
138     public:
139         bool m_isCheckingForDefaultMarkViolation;
140         bool m_isDraining;
141 #endif
142     };
143
144     inline MarkStack::MarkStack(void* jsArrayVPtr)
145         : m_jsArrayVPtr(jsArrayVPtr)
146         , m_firstWeakReferenceHarvester(0)
147 #if !ASSERT_DISABLED
148         , m_isCheckingForDefaultMarkViolation(false)
149         , m_isDraining(false)
150 #endif
151     {
152     }
153
154     inline MarkStack::~MarkStack()
155     {
156         ASSERT(m_markSets.isEmpty());
157         ASSERT(m_values.isEmpty());
158     }
159
160     inline bool MarkStack::addOpaqueRoot(void* root)
161     {
162         return m_opaqueRoots.add(root).second;
163     }
164
165     inline bool MarkStack::containsOpaqueRoot(void* root)
166     {
167         return m_opaqueRoots.contains(root);
168     }
169
170     inline int MarkStack::opaqueRootCount()
171     {
172         return m_opaqueRoots.size();
173     }
174
175     inline MarkSet::MarkSet(JSValue* values, JSValue* end)
176             : m_values(values)
177             , m_end(end)
178         {
179             ASSERT(values);
180         }
181
182     inline void* MarkStack::allocateStack(size_t size)
183     {
184         return OSAllocator::reserveAndCommit(size);
185     }
186
187     inline void MarkStack::releaseStack(void* addr, size_t size)
188     {
189         OSAllocator::decommitAndRelease(addr, size);
190     }
191
192     template <typename T> inline MarkStackArray<T>::MarkStackArray()
193         : m_top(0)
194         , m_allocated(pageSize())
195         , m_capacity(m_allocated / sizeof(T))
196     {
197         m_data = reinterpret_cast<T*>(MarkStack::allocateStack(m_allocated));
198     }
199
200     template <typename T> inline MarkStackArray<T>::~MarkStackArray()
201     {
202         MarkStack::releaseStack(m_data, m_allocated);
203     }
204
205     template <typename T> inline void MarkStackArray<T>::expand()
206     {
207         size_t oldAllocation = m_allocated;
208         m_allocated *= 2;
209         m_capacity = m_allocated / sizeof(T);
210         void* newData = MarkStack::allocateStack(m_allocated);
211         memcpy(newData, m_data, oldAllocation);
212         MarkStack::releaseStack(m_data, oldAllocation);
213         m_data = reinterpret_cast<T*>(newData);
214     }
215
216     template <typename T> inline void MarkStackArray<T>::append(const T& v)
217     {
218         if (m_top == m_capacity)
219             expand();
220         m_data[m_top++] = v;
221     }
222
223     template <typename T> inline T MarkStackArray<T>::removeLast()
224     {
225         ASSERT(m_top);
226         return m_data[--m_top];
227     }
228     
229     template <typename T> inline T& MarkStackArray<T>::last()
230     {
231         ASSERT(m_top);
232         return m_data[m_top - 1];
233     }
234
235     template <typename T> inline bool MarkStackArray<T>::isEmpty()
236     {
237         return m_top == 0;
238     }
239
240     template <typename T> inline size_t MarkStackArray<T>::size()
241     {
242         return m_top;
243     }
244
245     template <typename T> inline void MarkStackArray<T>::shrinkAllocation(size_t size)
246     {
247         ASSERT(size <= m_allocated);
248         ASSERT(isPageAligned(size));
249         if (size == m_allocated)
250             return;
251 #if OS(WINDOWS) || OS(SYMBIAN) || PLATFORM(BREWMP)
252         // We cannot release a part of a region with VirtualFree.  To get around this,
253         // we'll release the entire region and reallocate the size that we want.
254         MarkStack::releaseStack(m_data, m_allocated);
255         m_data = reinterpret_cast<T*>(MarkStack::allocateStack(size));
256 #else
257         MarkStack::releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size);
258 #endif
259         m_allocated = size;
260         m_capacity = m_allocated / sizeof(T);
261     }
262
263     inline void MarkStack::append(JSValue* slot, size_t count)
264     {
265         if (!count)
266             return;
267 #if ENABLE(GC_VALIDATION)
268         validateSet(slot, count);
269 #endif
270         m_markSets.append(MarkSet(slot, slot + count));
271     }
272
273     template<typename T>
274     inline void MarkStack::appendUnbarrieredPointer(T** slot)
275     {
276         ASSERT(slot);
277         JSCell* value = *slot;
278         if (value)
279             internalAppend(value);
280     }
281     
282     ALWAYS_INLINE void MarkStack::append(JSValue* value)
283     {
284         ASSERT(value);
285         internalAppend(*value);
286     }
287
288     ALWAYS_INLINE void MarkStack::append(JSCell** value)
289     {
290         ASSERT(value);
291         internalAppend(*value);
292     }
293
294     ALWAYS_INLINE void MarkStack::internalAppend(JSValue value)
295     {
296         ASSERT(value);
297 #if ENABLE(GC_VALIDATION)
298         validateValue(value);
299 #endif
300         if (value.isCell())
301             internalAppend(value.asCell());
302     }
303
304     class SlotVisitor;
305
306 } // namespace JSC
307
308 #endif