• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "JSValue.h"
30 #include "Register.h"
31 #include "WriteBarrier.h"
32 #include <wtf/HashSet.h>
33 #include <wtf/Vector.h>
34 #include <wtf/Noncopyable.h>
35 #include <wtf/OSAllocator.h>
36 
37 namespace JSC {
38 
39     class ConservativeRoots;
40     class JSGlobalData;
41     class Register;
42 
43     enum MarkSetProperties { MayContainNullValues, NoNullValues };
44 
45     class MarkStack {
46         WTF_MAKE_NONCOPYABLE(MarkStack);
47     public:
MarkStack(void * jsArrayVPtr)48         MarkStack(void* jsArrayVPtr)
49             : m_jsArrayVPtr(jsArrayVPtr)
50 #if !ASSERT_DISABLED
51             , m_isCheckingForDefaultMarkViolation(false)
52             , m_isDraining(false)
53 #endif
54         {
55         }
56 
~MarkStack()57         ~MarkStack()
58         {
59             ASSERT(m_markSets.isEmpty());
60             ASSERT(m_values.isEmpty());
61         }
62 
63         void deprecatedAppend(JSCell**);
64         template <typename T> void append(WriteBarrierBase<T>*);
65 
66         void appendValues(WriteBarrierBase<Unknown>* barriers, size_t count, MarkSetProperties properties = NoNullValues)
67         {
68             JSValue* values = barriers->slot();
69             if (count)
70                 m_markSets.append(MarkSet(values, values + count, properties));
71         }
72 
73         void append(ConservativeRoots&);
74 
addOpaqueRoot(void * root)75         bool addOpaqueRoot(void* root) { return m_opaqueRoots.add(root).second; }
containsOpaqueRoot(void * root)76         bool containsOpaqueRoot(void* root) { return m_opaqueRoots.contains(root); }
opaqueRootCount()77         int opaqueRootCount() { return m_opaqueRoots.size(); }
78 
79         void drain();
80         void reset();
81 
82     private:
83         friend class HeapRootMarker; // Allowed to mark a JSValue* or JSCell** directly.
84         void append(JSValue*);
85         void append(JSValue*, size_t count);
86         void append(JSCell**);
87 
88         void internalAppend(JSCell*);
89         void internalAppend(JSValue);
90         void markChildren(JSCell*);
91 
92         struct MarkSet {
MarkSetMarkSet93             MarkSet(JSValue* values, JSValue* end, MarkSetProperties properties)
94                 : m_values(values)
95                 , m_end(end)
96                 , m_properties(properties)
97             {
98                 ASSERT(values);
99             }
100             JSValue* m_values;
101             JSValue* m_end;
102             MarkSetProperties m_properties;
103         };
104 
allocateStack(size_t size)105         static void* allocateStack(size_t size) { return OSAllocator::reserveAndCommit(size); }
releaseStack(void * addr,size_t size)106         static void releaseStack(void* addr, size_t size) { OSAllocator::decommitAndRelease(addr, size); }
107 
108         static void initializePagesize();
pageSize()109         static size_t pageSize()
110         {
111             if (!s_pageSize)
112                 initializePagesize();
113             return s_pageSize;
114         }
115 
116         template <typename T> struct MarkStackArray {
MarkStackArrayMarkStackArray117             MarkStackArray()
118                 : m_top(0)
119                 , m_allocated(MarkStack::pageSize())
120                 , m_capacity(m_allocated / sizeof(T))
121             {
122                 m_data = reinterpret_cast<T*>(allocateStack(m_allocated));
123             }
124 
~MarkStackArrayMarkStackArray125             ~MarkStackArray()
126             {
127                 releaseStack(m_data, m_allocated);
128             }
129 
expandMarkStackArray130             void expand()
131             {
132                 size_t oldAllocation = m_allocated;
133                 m_allocated *= 2;
134                 m_capacity = m_allocated / sizeof(T);
135                 void* newData = allocateStack(m_allocated);
136                 memcpy(newData, m_data, oldAllocation);
137                 releaseStack(m_data, oldAllocation);
138                 m_data = reinterpret_cast<T*>(newData);
139             }
140 
appendMarkStackArray141             inline void append(const T& v)
142             {
143                 if (m_top == m_capacity)
144                     expand();
145                 m_data[m_top++] = v;
146             }
147 
removeLastMarkStackArray148             inline T removeLast()
149             {
150                 ASSERT(m_top);
151                 return m_data[--m_top];
152             }
153 
lastMarkStackArray154             inline T& last()
155             {
156                 ASSERT(m_top);
157                 return m_data[m_top - 1];
158             }
159 
isEmptyMarkStackArray160             inline bool isEmpty()
161             {
162                 return m_top == 0;
163             }
164 
sizeMarkStackArray165             inline size_t size() { return m_top; }
166 
shrinkAllocationMarkStackArray167             inline void shrinkAllocation(size_t size)
168             {
169                 ASSERT(size <= m_allocated);
170                 ASSERT(0 == (size % MarkStack::pageSize()));
171                 if (size == m_allocated)
172                     return;
173 #if OS(WINDOWS) || OS(SYMBIAN) || PLATFORM(BREWMP)
174                 // We cannot release a part of a region with VirtualFree.  To get around this,
175                 // we'll release the entire region and reallocate the size that we want.
176                 releaseStack(m_data, m_allocated);
177                 m_data = reinterpret_cast<T*>(allocateStack(size));
178 #else
179                 releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size);
180 #endif
181                 m_allocated = size;
182                 m_capacity = m_allocated / sizeof(T);
183             }
184 
185         private:
186             size_t m_top;
187             size_t m_allocated;
188             size_t m_capacity;
189             T* m_data;
190         };
191 
192         void* m_jsArrayVPtr;
193         MarkStackArray<MarkSet> m_markSets;
194         MarkStackArray<JSCell*> m_values;
195         static size_t s_pageSize;
196         HashSet<void*> m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector.
197 
198 #if !ASSERT_DISABLED
199     public:
200         bool m_isCheckingForDefaultMarkViolation;
201         bool m_isDraining;
202 #endif
203     };
204 
append(JSValue * slot,size_t count)205     inline void MarkStack::append(JSValue* slot, size_t count)
206     {
207         if (!count)
208             return;
209         m_markSets.append(MarkSet(slot, slot + count, NoNullValues));
210     }
211 
append(WriteBarrierBase<T> * slot)212     template <typename T> inline void MarkStack::append(WriteBarrierBase<T>* slot)
213     {
214         internalAppend(*slot->slot());
215     }
216 
deprecatedAppend(JSCell ** value)217     ALWAYS_INLINE void MarkStack::deprecatedAppend(JSCell** value)
218     {
219         ASSERT(value);
220         internalAppend(*value);
221     }
222 
append(JSValue * value)223     ALWAYS_INLINE void MarkStack::append(JSValue* value)
224     {
225         ASSERT(value);
226         internalAppend(*value);
227     }
228 
append(JSCell ** value)229     ALWAYS_INLINE void MarkStack::append(JSCell** value)
230     {
231         ASSERT(value);
232         internalAppend(*value);
233     }
234 
internalAppend(JSValue value)235     ALWAYS_INLINE void MarkStack::internalAppend(JSValue value)
236     {
237         ASSERT(value);
238         if (value.isCell())
239             internalAppend(value.asCell());
240     }
241 
242     // Privileged class for marking JSValues directly. It is only safe to use
243     // this class to mark direct heap roots that are marked during every GC pass.
244     // All other references should be wrapped in WriteBarriers and marked through
245     // the MarkStack.
246     class HeapRootMarker {
247     private:
248         friend class Heap;
249         HeapRootMarker(MarkStack&);
250 
251     public:
252         void mark(JSValue*);
253         void mark(JSValue*, size_t);
254         void mark(JSString**);
255         void mark(JSCell**);
256 
257         MarkStack& markStack();
258 
259     private:
260         MarkStack& m_markStack;
261     };
262 
HeapRootMarker(MarkStack & markStack)263     inline HeapRootMarker::HeapRootMarker(MarkStack& markStack)
264         : m_markStack(markStack)
265     {
266     }
267 
mark(JSValue * slot)268     inline void HeapRootMarker::mark(JSValue* slot)
269     {
270         m_markStack.append(slot);
271     }
272 
mark(JSValue * slot,size_t count)273     inline void HeapRootMarker::mark(JSValue* slot, size_t count)
274     {
275         m_markStack.append(slot, count);
276     }
277 
mark(JSString ** slot)278     inline void HeapRootMarker::mark(JSString** slot)
279     {
280         m_markStack.append(reinterpret_cast<JSCell**>(slot));
281     }
282 
mark(JSCell ** slot)283     inline void HeapRootMarker::mark(JSCell** slot)
284     {
285         m_markStack.append(slot);
286     }
287 
markStack()288     inline MarkStack& HeapRootMarker::markStack()
289     {
290         return m_markStack;
291     }
292 
293 } // namespace JSC
294 
295 #endif
296