]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/WriteBarrier.h
89989479529c003e9d6d1b9764317106aa5d08b1
[apple/javascriptcore.git] / runtime / WriteBarrier.h
1 /*
2 * Copyright (C) 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #ifndef WriteBarrier_h
27 #define WriteBarrier_h
28
29 #include "HandleTypes.h"
30 #include "Heap.h"
31 #include "TypeTraits.h"
32
33 namespace JSC {
34
35 class JSCell;
36 class JSGlobalData;
37 class JSGlobalObject;
38
39 template<class T> class WriteBarrierBase;
40 template<> class WriteBarrierBase<JSValue>;
41
42 void slowValidateCell(JSCell*);
43 void slowValidateCell(JSGlobalObject*);
44
45 #if ENABLE(GC_VALIDATION)
46 template<class T> inline void validateCell(T cell)
47 {
48 ASSERT_GC_OBJECT_INHERITS(cell, &WTF::RemovePointer<T>::Type::s_info);
49 }
50
51 template<> inline void validateCell<JSCell*>(JSCell* cell)
52 {
53 slowValidateCell(cell);
54 }
55
56 template<> inline void validateCell<JSGlobalObject*>(JSGlobalObject* globalObject)
57 {
58 slowValidateCell(globalObject);
59 }
60 #else
61 template<class T> inline void validateCell(T)
62 {
63 }
64 #endif
65
66 // We have a separate base class with no constructors for use in Unions.
67 template <typename T> class WriteBarrierBase {
68 public:
69 void set(JSGlobalData& globalData, const JSCell* owner, T* value)
70 {
71 ASSERT(value);
72 validateCell(value);
73 setEarlyValue(globalData, owner, value);
74 }
75
76 void setMayBeNull(JSGlobalData& globalData, const JSCell* owner, T* value)
77 {
78 if (value)
79 validateCell(value);
80 setEarlyValue(globalData, owner, value);
81 }
82
83 // Should only be used by JSCell during early initialisation
84 // when some basic types aren't yet completely instantiated
85 void setEarlyValue(JSGlobalData&, const JSCell* owner, T* value)
86 {
87 this->m_cell = reinterpret_cast<JSCell*>(value);
88 Heap::writeBarrier(owner, this->m_cell);
89 #if ENABLE(JSC_ZOMBIES)
90 ASSERT(!isZombie(owner));
91 ASSERT(!isZombie(m_cell));
92 #endif
93 }
94
95 T* get() const
96 {
97 if (m_cell)
98 validateCell(m_cell);
99 return reinterpret_cast<T*>(m_cell);
100 }
101
102 T* operator*() const
103 {
104 ASSERT(m_cell);
105 #if ENABLE(JSC_ZOMBIES)
106 ASSERT(!isZombie(m_cell));
107 #endif
108 validateCell<T>(static_cast<T*>(m_cell));
109 return static_cast<T*>(m_cell);
110 }
111
112 T* operator->() const
113 {
114 ASSERT(m_cell);
115 validateCell(static_cast<T*>(m_cell));
116 return static_cast<T*>(m_cell);
117 }
118
119 void clear() { m_cell = 0; }
120
121 JSCell** slot() { return &m_cell; }
122
123 typedef T* (WriteBarrierBase::*UnspecifiedBoolType);
124 operator UnspecifiedBoolType*() const { return m_cell ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
125
126 bool operator!() const { return !m_cell; }
127
128 void setWithoutWriteBarrier(T* value)
129 {
130 this->m_cell = reinterpret_cast<JSCell*>(value);
131 #if ENABLE(JSC_ZOMBIES)
132 ASSERT(!m_cell || !isZombie(m_cell));
133 #endif
134 }
135
136 #if ENABLE(GC_VALIDATION)
137 T* unvalidatedGet() const { return reinterpret_cast<T*>(m_cell); }
138 #endif
139
140 private:
141 JSCell* m_cell;
142 };
143
144 template <> class WriteBarrierBase<Unknown> {
145 public:
146 void set(JSGlobalData&, const JSCell* owner, JSValue value)
147 {
148 #if ENABLE(JSC_ZOMBIES)
149 ASSERT(!isZombie(owner));
150 ASSERT(!value.isZombie());
151 #endif
152 m_value = JSValue::encode(value);
153 Heap::writeBarrier(owner, value);
154 }
155
156 void setWithoutWriteBarrier(JSValue value)
157 {
158 #if ENABLE(JSC_ZOMBIES)
159 ASSERT(!value.isZombie());
160 #endif
161 m_value = JSValue::encode(value);
162 }
163
164 JSValue get() const
165 {
166 return JSValue::decode(m_value);
167 }
168 void clear() { m_value = JSValue::encode(JSValue()); }
169 void setUndefined() { m_value = JSValue::encode(jsUndefined()); }
170 bool isNumber() const { return get().isNumber(); }
171 bool isObject() const { return get().isObject(); }
172 bool isNull() const { return get().isNull(); }
173 bool isGetterSetter() const { return get().isGetterSetter(); }
174
175 JSValue* slot()
176 {
177 union {
178 EncodedJSValue* v;
179 JSValue* slot;
180 } u;
181 u.v = &m_value;
182 return u.slot;
183 }
184
185 typedef JSValue (WriteBarrierBase::*UnspecifiedBoolType);
186 operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
187 bool operator!() const { return !get(); }
188
189 private:
190 EncodedJSValue m_value;
191 };
192
193 template <typename T> class WriteBarrier : public WriteBarrierBase<T> {
194 public:
195 WriteBarrier()
196 {
197 this->setWithoutWriteBarrier(0);
198 }
199
200 WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value)
201 {
202 this->set(globalData, owner, value);
203 }
204
205 enum MayBeNullTag { MayBeNull };
206 WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value, MayBeNullTag)
207 {
208 this->setMayBeNull(globalData, owner, value);
209 }
210 };
211
212 template <> class WriteBarrier<Unknown> : public WriteBarrierBase<Unknown> {
213 public:
214 WriteBarrier()
215 {
216 this->setWithoutWriteBarrier(JSValue());
217 }
218
219 WriteBarrier(JSGlobalData& globalData, const JSCell* owner, JSValue value)
220 {
221 this->set(globalData, owner, value);
222 }
223 };
224
225 template <typename U, typename V> inline bool operator==(const WriteBarrierBase<U>& lhs, const WriteBarrierBase<V>& rhs)
226 {
227 return lhs.get() == rhs.get();
228 }
229
230 // MarkStack functions
231
232 template<typename T> inline void MarkStack::append(WriteBarrierBase<T>* slot)
233 {
234 internalAppend(*slot->slot());
235 }
236
237 inline void MarkStack::appendValues(WriteBarrierBase<Unknown>* barriers, size_t count, MarkSetProperties properties)
238 {
239 JSValue* values = barriers->slot();
240 #if ENABLE(GC_VALIDATION)
241 validateSet(values, count);
242 #endif
243 if (count)
244 m_markSets.append(MarkSet(values, values + count, properties));
245 }
246
247 } // namespace JSC
248
249 #endif // WriteBarrier_h