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