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 "JSValue.h"
30
31namespace JSC {
32class JSCell;
33class JSGlobalData;
34
35inline void writeBarrier(JSGlobalData&, const JSCell*, JSValue)
36{
37}
38
39inline void writeBarrier(JSGlobalData&, const JSCell*, JSCell*)
40{
41}
42
43typedef enum { } Unknown;
44typedef JSValue* HandleSlot;
45
46template <typename T> struct JSValueChecker {
47    static const bool IsJSValue = false;
48};
49
50template <> struct JSValueChecker<JSValue> {
51    static const bool IsJSValue = true;
52};
53
54// We have a separate base class with no constructors for use in Unions.
55template <typename T> class WriteBarrierBase {
56public:
57    COMPILE_ASSERT(!JSValueChecker<T>::IsJSValue, WriteBarrier_JSValue_is_invalid__use_unknown);
58    void set(JSGlobalData& globalData, const JSCell* owner, T* value)
59    {
60        this->m_cell = reinterpret_cast<JSCell*>(value);
61        writeBarrier(globalData, owner, this->m_cell);
62#if ENABLE(JSC_ZOMBIES)
63        ASSERT(!isZombie(owner));
64        ASSERT(!isZombie(m_cell));
65#endif
66    }
67
68    T* get() const
69    {
70        return reinterpret_cast<T*>(m_cell);
71    }
72
73    T* operator*() const
74    {
75        ASSERT(m_cell);
76#if ENABLE(JSC_ZOMBIES)
77        ASSERT(!isZombie(m_cell));
78#endif
79        return static_cast<T*>(m_cell);
80    }
81
82    T* operator->() const
83    {
84        ASSERT(m_cell);
85        return static_cast<T*>(m_cell);
86    }
87
88    void clear() { m_cell = 0; }
89
90    JSCell** slot() { return &m_cell; }
91
92    typedef T* (WriteBarrierBase::*UnspecifiedBoolType);
93    operator UnspecifiedBoolType*() const { return m_cell ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
94
95    bool operator!() const { return !m_cell; }
96
97    void setWithoutWriteBarrier(T* value)
98    {
99        this->m_cell = reinterpret_cast<JSCell*>(value);
100#if ENABLE(JSC_ZOMBIES)
101        ASSERT(!m_cell || !isZombie(m_cell));
102#endif
103    }
104
105private:
106    JSCell* m_cell;
107};
108
109template <> class WriteBarrierBase<Unknown> {
110public:
111    void set(JSGlobalData& globalData, const JSCell* owner, JSValue value)
112    {
113#if ENABLE(JSC_ZOMBIES)
114        ASSERT(!isZombie(owner));
115        ASSERT(!value.isZombie());
116#endif
117        m_value = JSValue::encode(value);
118        writeBarrier(globalData, owner, value);
119    }
120    void setWithoutWriteBarrier(JSValue value)
121    {
122#if ENABLE(JSC_ZOMBIES)
123        ASSERT(!value.isZombie());
124#endif
125        m_value = JSValue::encode(value);
126    }
127
128    JSValue get() const
129    {
130        return JSValue::decode(m_value);
131    }
132    void clear() { m_value = JSValue::encode(JSValue()); }
133    void setUndefined() { m_value = JSValue::encode(jsUndefined()); }
134    bool isNumber() const { return get().isNumber(); }
135    bool isObject() const { return get().isObject(); }
136    bool isNull() const { return get().isNull(); }
137    bool isGetterSetter() const { return get().isGetterSetter(); }
138
139    JSValue* slot()
140    {
141        union {
142            EncodedJSValue* v;
143            JSValue* slot;
144        } u;
145        u.v = &m_value;
146        return u.slot;
147    }
148
149    typedef JSValue (WriteBarrierBase::*UnspecifiedBoolType);
150    operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
151    bool operator!() const { return !get(); }
152
153private:
154    EncodedJSValue m_value;
155};
156
157template <typename T> class WriteBarrier : public WriteBarrierBase<T> {
158public:
159    WriteBarrier()
160    {
161        this->setWithoutWriteBarrier(0);
162    }
163
164    WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value)
165    {
166        this->set(globalData, owner, value);
167    }
168};
169
170template <> class WriteBarrier<Unknown> : public WriteBarrierBase<Unknown> {
171public:
172    WriteBarrier()
173    {
174        this->setWithoutWriteBarrier(JSValue());
175    }
176
177    WriteBarrier(JSGlobalData& globalData, const JSCell* owner, JSValue value)
178    {
179        this->set(globalData, owner, value);
180    }
181};
182
183template <typename U, typename V> inline bool operator==(const WriteBarrierBase<U>& lhs, const WriteBarrierBase<V>& rhs)
184{
185    return lhs.get() == rhs.get();
186}
187
188} // namespace JSC
189
190#endif // WriteBarrier_h
191