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