Unreviewed, rolling out r109837.
[WebKit-https.git] / Source / JavaScriptCore / 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 "GCAssertions.h"
30 #include "HandleTypes.h"
31 #include "Heap.h"
32 #include "SamplingCounter.h"
33 #include "TypeTraits.h"
34
35 namespace JSC {
36
37 class JSCell;
38 class JSGlobalData;
39 class JSGlobalObject;
40
41 template<class T> class WriteBarrierBase;
42 template<> class WriteBarrierBase<JSValue>;
43
44 JS_EXPORT_PRIVATE void slowValidateCell(JSCell*);
45 JS_EXPORT_PRIVATE void slowValidateCell(JSGlobalObject*);
46     
47 #if ENABLE(GC_VALIDATION)
48 template<class T> inline void validateCell(T cell)
49 {
50     ASSERT_GC_OBJECT_INHERITS(cell, &WTF::RemovePointer<T>::Type::s_info);
51 }
52
53 template<> inline void validateCell<JSCell*>(JSCell* cell)
54 {
55     slowValidateCell(cell);
56 }
57
58 template<> inline void validateCell<JSGlobalObject*>(JSGlobalObject* globalObject)
59 {
60     slowValidateCell(globalObject);
61 }
62 #else
63 template<class T> inline void validateCell(T)
64 {
65 }
66 #endif
67
68 // We have a separate base class with no constructors for use in Unions.
69 template <typename T> class WriteBarrierBase {
70 public:
71     void set(JSGlobalData& globalData, const JSCell* owner, T* value)
72     {
73         ASSERT(value);
74         validateCell(value);
75         setEarlyValue(globalData, owner, value);
76     }
77     
78     // This is meant to be used like operator=, but is called copyFrom instead, in
79     // order to kindly inform the C++ compiler that its advice is not appreciated.
80     void copyFrom(const WriteBarrierBase<T>& other)
81     {
82         m_cell = other.m_cell;
83     }
84
85     void setMayBeNull(JSGlobalData& globalData, const JSCell* owner, T* value)
86     {
87         if (value)
88             validateCell(value);
89         setEarlyValue(globalData, owner, value);
90     }
91
92     // Should only be used by JSCell during early initialisation
93     // when some basic types aren't yet completely instantiated
94     void setEarlyValue(JSGlobalData&, const JSCell* owner, T* value)
95     {
96         this->m_cell = reinterpret_cast<JSCell*>(value);
97         Heap::writeBarrier(owner, this->m_cell);
98     }
99     
100     T* get() const
101     {
102         if (m_cell)
103             validateCell(m_cell);
104         return reinterpret_cast<T*>(static_cast<void*>(m_cell));
105     }
106
107     T* operator*() const
108     {
109         ASSERT(m_cell);
110         validateCell<T>(static_cast<T*>(m_cell));
111         return static_cast<T*>(m_cell);
112     }
113
114     T* operator->() const
115     {
116         ASSERT(m_cell);
117         validateCell(static_cast<T*>(m_cell));
118         return static_cast<T*>(m_cell);
119     }
120
121     void clear() { m_cell = 0; }
122     
123     JSCell** slot() { return &m_cell; }
124     
125     typedef T* (WriteBarrierBase::*UnspecifiedBoolType);
126     operator UnspecifiedBoolType*() const { return m_cell ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
127     
128     bool operator!() const { return !m_cell; }
129
130     void setWithoutWriteBarrier(T* value)
131     {
132 #if ENABLE(WRITE_BARRIER_PROFILING)
133         WriteBarrierCounters::usesWithoutBarrierFromCpp.count();
134 #endif
135         this->m_cell = reinterpret_cast<JSCell*>(value);
136     }
137
138 #if ENABLE(GC_VALIDATION)
139     T* unvalidatedGet() const { return reinterpret_cast<T*>(static_cast<void*>(m_cell)); }
140 #endif
141
142 private:
143     JSCell* m_cell;
144 };
145
146 template <> class WriteBarrierBase<Unknown> {
147 public:
148     void set(JSGlobalData&, const JSCell* owner, JSValue value)
149     {
150         m_value = JSValue::encode(value);
151         Heap::writeBarrier(owner, value);
152     }
153
154     void setWithoutWriteBarrier(JSValue value)
155     {
156         m_value = JSValue::encode(value);
157     }
158
159     JSValue get() const
160     {
161         return JSValue::decode(m_value);
162     }
163     void clear() { m_value = JSValue::encode(JSValue()); }
164     void setUndefined() { m_value = JSValue::encode(jsUndefined()); }
165     bool isNumber() const { return get().isNumber(); }
166     bool isObject() const { return get().isObject(); }
167     bool isNull() const { return get().isNull(); }
168     bool isGetterSetter() const { return get().isGetterSetter(); }
169     
170     JSValue* slot()
171     { 
172         union {
173             EncodedJSValue* v;
174             JSValue* slot;
175         } u;
176         u.v = &m_value;
177         return u.slot;
178     }
179     
180     typedef JSValue (WriteBarrierBase::*UnspecifiedBoolType);
181     operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
182     bool operator!() const { return !get(); } 
183     
184 private:
185     EncodedJSValue m_value;
186 };
187
188 template <typename T> class WriteBarrier : public WriteBarrierBase<T> {
189 public:
190     WriteBarrier()
191     {
192         this->setWithoutWriteBarrier(0);
193     }
194
195     WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value)
196     {
197         this->set(globalData, owner, value);
198     }
199
200     enum MayBeNullTag { MayBeNull };
201     WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value, MayBeNullTag)
202     {
203         this->setMayBeNull(globalData, owner, value);
204     }
205 };
206
207 template <> class WriteBarrier<Unknown> : public WriteBarrierBase<Unknown> {
208 public:
209     WriteBarrier()
210     {
211         this->setWithoutWriteBarrier(JSValue());
212     }
213
214     WriteBarrier(JSGlobalData& globalData, const JSCell* owner, JSValue value)
215     {
216         this->set(globalData, owner, value);
217     }
218 };
219
220 template <typename U, typename V> inline bool operator==(const WriteBarrierBase<U>& lhs, const WriteBarrierBase<V>& rhs)
221 {
222     return lhs.get() == rhs.get();
223 }
224
225 // MarkStack functions
226
227 template<typename T> inline void MarkStack::append(WriteBarrierBase<T>* slot)
228 {
229     internalAppend(*slot->slot());
230 }
231
232 ALWAYS_INLINE void MarkStack::appendValues(WriteBarrierBase<Unknown>* barriers, size_t count)
233 {
234     append(barriers->slot(), count);
235 }
236
237 } // namespace JSC
238
239 #endif // WriteBarrier_h