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 "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>
43 class ConservativeRoots;
47 template<typename T> class WriteBarrierBase;
48 template<typename T> class JITWriteBarrier;
51 MarkSet(JSValue* values, JSValue* end);
57 template<typename T> class MarkStackArray {
63 void append(const T&);
71 void shrinkAllocation(size_t);
81 WTF_MAKE_NONCOPYABLE(MarkStack);
82 friend class HeapRootVisitor; // Allowed to mark a JSValue* or JSCell** directly.
85 static void* allocateStack(size_t);
86 static void releaseStack(void*, size_t);
88 MarkStack(void* jsArrayVPtr);
91 void append(ConservativeRoots&);
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);
98 inline void appendUnbarrieredPointer(T**);
100 bool addOpaqueRoot(void*);
101 bool containsOpaqueRoot(void*);
102 int opaqueRootCount();
106 #if ENABLE(SIMPLE_HEAP_PROFILING)
107 VTableSpectrum m_visitedTypeCounts;
110 void addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)
112 if (weakReferenceHarvester->m_nextAndFlag & 1)
114 weakReferenceHarvester->m_nextAndFlag = reinterpret_cast<uintptr_t>(m_firstWeakReferenceHarvester) | 1;
115 m_firstWeakReferenceHarvester = weakReferenceHarvester;
119 #if ENABLE(GC_VALIDATION)
120 static void validateSet(JSValue*, size_t);
122 static void validateValue(JSValue);
124 void append(JSValue*);
125 void append(JSValue*, size_t count);
126 void append(JSCell**);
128 void internalAppend(JSCell*);
129 void internalAppend(JSValue);
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;
139 bool m_isCheckingForDefaultMarkViolation;
144 inline MarkStack::MarkStack(void* jsArrayVPtr)
145 : m_jsArrayVPtr(jsArrayVPtr)
146 , m_firstWeakReferenceHarvester(0)
148 , m_isCheckingForDefaultMarkViolation(false)
149 , m_isDraining(false)
154 inline MarkStack::~MarkStack()
156 ASSERT(m_markSets.isEmpty());
157 ASSERT(m_values.isEmpty());
160 inline bool MarkStack::addOpaqueRoot(void* root)
162 return m_opaqueRoots.add(root).second;
165 inline bool MarkStack::containsOpaqueRoot(void* root)
167 return m_opaqueRoots.contains(root);
170 inline int MarkStack::opaqueRootCount()
172 return m_opaqueRoots.size();
175 inline MarkSet::MarkSet(JSValue* values, JSValue* end)
182 inline void* MarkStack::allocateStack(size_t size)
184 return OSAllocator::reserveAndCommit(size);
187 inline void MarkStack::releaseStack(void* addr, size_t size)
189 OSAllocator::decommitAndRelease(addr, size);
192 template <typename T> inline MarkStackArray<T>::MarkStackArray()
194 , m_allocated(pageSize())
195 , m_capacity(m_allocated / sizeof(T))
197 m_data = reinterpret_cast<T*>(MarkStack::allocateStack(m_allocated));
200 template <typename T> inline MarkStackArray<T>::~MarkStackArray()
202 MarkStack::releaseStack(m_data, m_allocated);
205 template <typename T> inline void MarkStackArray<T>::expand()
207 size_t oldAllocation = m_allocated;
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);
216 template <typename T> inline void MarkStackArray<T>::append(const T& v)
218 if (m_top == m_capacity)
223 template <typename T> inline T MarkStackArray<T>::removeLast()
226 return m_data[--m_top];
229 template <typename T> inline T& MarkStackArray<T>::last()
232 return m_data[m_top - 1];
235 template <typename T> inline bool MarkStackArray<T>::isEmpty()
240 template <typename T> inline size_t MarkStackArray<T>::size()
245 template <typename T> inline void MarkStackArray<T>::shrinkAllocation(size_t size)
247 ASSERT(size <= m_allocated);
248 ASSERT(isPageAligned(size));
249 if (size == m_allocated)
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));
257 MarkStack::releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size);
260 m_capacity = m_allocated / sizeof(T);
263 inline void MarkStack::append(JSValue* slot, size_t count)
267 #if ENABLE(GC_VALIDATION)
268 validateSet(slot, count);
270 m_markSets.append(MarkSet(slot, slot + count));
274 inline void MarkStack::appendUnbarrieredPointer(T** slot)
277 JSCell* value = *slot;
279 internalAppend(value);
282 ALWAYS_INLINE void MarkStack::append(JSValue* value)
285 internalAppend(*value);
288 ALWAYS_INLINE void MarkStack::append(JSCell** value)
291 internalAppend(*value);
294 ALWAYS_INLINE void MarkStack::internalAppend(JSValue value)
297 #if ENABLE(GC_VALIDATION)
298 validateValue(value);
301 internalAppend(value.asCell());