Foo::s_info should be Foo::info(), so that you can change how the s_info is actually...
[WebKit-https.git] / Source / JavaScriptCore / runtime / WriteBarrier.h
1 /*
2  * Copyright (C) 2011, 2013 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 <wtf/TypeTraits.h>
34
35 namespace JSC {
36
37 class JSCell;
38 class VM;
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::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(VM& vm, const JSCell* owner, T* value)
72     {
73         ASSERT(value);
74         validateCell(value);
75         setEarlyValue(vm, 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(VM& vm, const JSCell* owner, T* value)
86     {
87         if (value)
88             validateCell(value);
89         setEarlyValue(vm, 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(VM&, 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         // Copy m_cell to a local to avoid multiple-read issues. (See <http://webkit.org/b/110854>)
103         JSCell* cell = m_cell;
104         if (cell)
105             validateCell(cell);
106         return reinterpret_cast<T*>(static_cast<void*>(cell));
107     }
108
109     T* operator*() const
110     {
111         ASSERT(m_cell);
112         validateCell<T>(static_cast<T*>(m_cell));
113         return static_cast<T*>(m_cell);
114     }
115
116     T* operator->() const
117     {
118         ASSERT(m_cell);
119         validateCell(static_cast<T*>(m_cell));
120         return static_cast<T*>(m_cell);
121     }
122
123     void clear() { m_cell = 0; }
124     
125     T** slot() { return reinterpret_cast<T**>(&m_cell); }
126     
127     typedef T* (WriteBarrierBase::*UnspecifiedBoolType);
128     operator UnspecifiedBoolType*() const { return m_cell ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
129     
130     bool operator!() const { return !m_cell; }
131
132     void setWithoutWriteBarrier(T* value)
133     {
134 #if ENABLE(WRITE_BARRIER_PROFILING)
135         WriteBarrierCounters::usesWithoutBarrierFromCpp.count();
136 #endif
137         this->m_cell = reinterpret_cast<JSCell*>(value);
138     }
139
140 #if ENABLE(GC_VALIDATION)
141     T* unvalidatedGet() const { return reinterpret_cast<T*>(static_cast<void*>(m_cell)); }
142 #endif
143
144 private:
145     JSCell* m_cell;
146 };
147
148 template <> class WriteBarrierBase<Unknown> {
149 public:
150     void set(VM&, const JSCell* owner, JSValue value)
151     {
152         m_value = JSValue::encode(value);
153         Heap::writeBarrier(owner, value);
154     }
155
156     void setWithoutWriteBarrier(JSValue value)
157     {
158         m_value = JSValue::encode(value);
159     }
160
161     JSValue get() const
162     {
163         return JSValue::decode(m_value);
164     }
165     void clear() { m_value = JSValue::encode(JSValue()); }
166     void setUndefined() { m_value = JSValue::encode(jsUndefined()); }
167     bool isNumber() const { return get().isNumber(); }
168     bool isObject() const { return get().isObject(); }
169     bool isNull() const { return get().isNull(); }
170     bool isGetterSetter() const { return get().isGetterSetter(); }
171     
172     JSValue* slot()
173     { 
174         union {
175             EncodedJSValue* v;
176             JSValue* slot;
177         } u;
178         u.v = &m_value;
179         return u.slot;
180     }
181     
182     int32_t* tagPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.tag; }
183     int32_t* payloadPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.payload; }
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(VM& vm, const JSCell* owner, T* value)
201     {
202         this->set(vm, owner, value);
203     }
204
205     enum MayBeNullTag { MayBeNull };
206     WriteBarrier(VM& vm, const JSCell* owner, T* value, MayBeNullTag)
207     {
208         this->setMayBeNull(vm, 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(VM& vm, const JSCell* owner, JSValue value)
220     {
221         this->set(vm, 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 } // namespace JSC
231
232 #endif // WriteBarrier_h