2 * Copyright (C) 2009, 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "HandleTypes.h"
32 #include <wtf/HashSet.h>
33 #include <wtf/Vector.h>
34 #include <wtf/Noncopyable.h>
35 #include <wtf/OSAllocator.h>
39 class ConservativeRoots
;
42 template<typename T
> class WriteBarrierBase
;
43 template<typename T
> class JITWriteBarrier
;
45 enum MarkSetProperties
{ MayContainNullValues
, NoNullValues
};
48 WTF_MAKE_NONCOPYABLE(MarkStack
);
50 MarkStack(void* jsArrayVPtr
)
51 : m_jsArrayVPtr(jsArrayVPtr
)
52 , m_shouldUnlinkCalls(false)
54 , m_isCheckingForDefaultMarkViolation(false)
62 ASSERT(m_markSets
.isEmpty());
63 ASSERT(m_values
.isEmpty());
66 template<typename T
> inline void append(JITWriteBarrier
<T
>*);
67 template<typename T
> inline void append(WriteBarrierBase
<T
>*);
68 inline void appendValues(WriteBarrierBase
<Unknown
>*, size_t count
, MarkSetProperties
= NoNullValues
);
70 void append(ConservativeRoots
&);
72 bool addOpaqueRoot(void* root
) { return m_opaqueRoots
.add(root
).second
; }
73 bool containsOpaqueRoot(void* root
) { return m_opaqueRoots
.contains(root
); }
74 int opaqueRootCount() { return m_opaqueRoots
.size(); }
79 bool shouldUnlinkCalls() const { return m_shouldUnlinkCalls
; }
80 void setShouldUnlinkCalls(bool shouldUnlinkCalls
) { m_shouldUnlinkCalls
= shouldUnlinkCalls
; }
83 friend class HeapRootVisitor
; // Allowed to mark a JSValue* or JSCell** directly.
85 #if ENABLE(GC_VALIDATION)
86 static void validateSet(JSValue
*, size_t);
87 static void validateValue(JSValue
);
90 void append(JSValue
*);
91 void append(JSValue
*, size_t count
);
92 void append(JSCell
**);
94 void internalAppend(JSCell
*);
95 void internalAppend(JSValue
);
96 void visitChildren(JSCell
*);
99 MarkSet(JSValue
* values
, JSValue
* end
, MarkSetProperties properties
)
102 , m_properties(properties
)
108 MarkSetProperties m_properties
;
111 static void* allocateStack(size_t size
) { return OSAllocator::reserveAndCommit(size
); }
112 static void releaseStack(void* addr
, size_t size
) { OSAllocator::decommitAndRelease(addr
, size
); }
114 static void initializePagesize();
115 static size_t pageSize()
118 initializePagesize();
122 template<typename T
> struct MarkStackArray
{
125 , m_allocated(MarkStack::pageSize())
126 , m_capacity(m_allocated
/ sizeof(T
))
128 m_data
= reinterpret_cast<T
*>(allocateStack(m_allocated
));
133 releaseStack(m_data
, m_allocated
);
138 size_t oldAllocation
= m_allocated
;
140 m_capacity
= m_allocated
/ sizeof(T
);
141 void* newData
= allocateStack(m_allocated
);
142 memcpy(newData
, m_data
, oldAllocation
);
143 releaseStack(m_data
, oldAllocation
);
144 m_data
= reinterpret_cast<T
*>(newData
);
147 inline void append(const T
& v
)
149 if (m_top
== m_capacity
)
154 inline T
removeLast()
157 return m_data
[--m_top
];
163 return m_data
[m_top
- 1];
166 inline bool isEmpty()
171 inline size_t size() { return m_top
; }
173 inline void shrinkAllocation(size_t size
)
175 ASSERT(size
<= m_allocated
);
176 ASSERT(0 == (size
% MarkStack::pageSize()));
177 if (size
== m_allocated
)
179 #if OS(WINDOWS) || OS(SYMBIAN) || PLATFORM(BREWMP)
180 // We cannot release a part of a region with VirtualFree. To get around this,
181 // we'll release the entire region and reallocate the size that we want.
182 releaseStack(m_data
, m_allocated
);
183 m_data
= reinterpret_cast<T
*>(allocateStack(size
));
185 releaseStack(reinterpret_cast<char*>(m_data
) + size
, m_allocated
- size
);
188 m_capacity
= m_allocated
/ sizeof(T
);
199 MarkStackArray
<MarkSet
> m_markSets
;
200 MarkStackArray
<JSCell
*> m_values
;
201 static size_t s_pageSize
;
202 HashSet
<void*> m_opaqueRoots
; // Handle-owning data structures not visible to the garbage collector.
203 bool m_shouldUnlinkCalls
;
207 bool m_isCheckingForDefaultMarkViolation
;
212 typedef MarkStack SlotVisitor
;
214 inline void MarkStack::append(JSValue
* slot
, size_t count
)
218 #if ENABLE(GC_VALIDATION)
219 validateSet(slot
, count
);
221 m_markSets
.append(MarkSet(slot
, slot
+ count
, NoNullValues
));
224 ALWAYS_INLINE
void MarkStack::append(JSValue
* value
)
227 internalAppend(*value
);
230 ALWAYS_INLINE
void MarkStack::append(JSCell
** value
)
233 internalAppend(*value
);
236 ALWAYS_INLINE
void MarkStack::internalAppend(JSValue value
)
239 #if ENABLE(GC_VALIDATION)
240 validateValue(value
);
243 internalAppend(value
.asCell());
246 // Privileged class for marking JSValues directly. It is only safe to use
247 // this class to mark direct heap roots that are marked during every GC pass.
248 // All other references should be wrapped in WriteBarriers and marked through
250 class HeapRootVisitor
{
253 HeapRootVisitor(SlotVisitor
&);
257 void mark(JSValue
*, size_t);
258 void mark(JSString
**);
261 SlotVisitor
& visitor();
264 SlotVisitor
& m_visitor
;
267 inline HeapRootVisitor::HeapRootVisitor(SlotVisitor
& visitor
)
272 inline void HeapRootVisitor::mark(JSValue
* slot
)
274 m_visitor
.append(slot
);
277 inline void HeapRootVisitor::mark(JSValue
* slot
, size_t count
)
279 m_visitor
.append(slot
, count
);
282 inline void HeapRootVisitor::mark(JSString
** slot
)
284 m_visitor
.append(reinterpret_cast<JSCell
**>(slot
));
287 inline void HeapRootVisitor::mark(JSCell
** slot
)
289 m_visitor
.append(slot
);
292 inline SlotVisitor
& HeapRootVisitor::visitor()