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 JITWriteBarrier_h
27#define JITWriteBarrier_h
28
29#if ENABLE(JIT)
30
31#include "MacroAssembler.h"
32#include "SlotVisitor.h"
33#include "UnusedPointer.h"
34#include "WriteBarrier.h"
35
36namespace JSC {
37
38class JSCell;
39class VM;
40
41// Needs to be even to appease some of the backends.
42#define JITWriteBarrierFlag ((void*)2)
43class JITWriteBarrierBase {
44public:
45    typedef void* (JITWriteBarrierBase::*UnspecifiedBoolType);
46    operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
47    bool operator!() const { return !get(); }
48
49    void setFlagOnBarrier()
50    {
51        ASSERT(!m_location);
52        m_location = CodeLocationDataLabelPtr(JITWriteBarrierFlag);
53    }
54
55    bool isFlagged() const
56    {
57        return !!m_location;
58    }
59
60    void setLocation(CodeLocationDataLabelPtr location)
61    {
62        ASSERT(!m_location);
63        m_location = location;
64    }
65
66    CodeLocationDataLabelPtr location() const
67    {
68        ASSERT((!!m_location) && m_location.executableAddress() != JITWriteBarrierFlag);
69        return m_location;
70    }
71
72    void clear() { clear(0); }
73    void clearToUnusedPointer() { clear(reinterpret_cast<void*>(unusedPointer)); }
74
75protected:
76    JITWriteBarrierBase()
77    {
78    }
79
80    void set(VM& vm, CodeLocationDataLabelPtr location, JSCell* owner, JSCell* value)
81    {
82        vm.heap.writeBarrier(owner, value);
83        m_location = location;
84        ASSERT(((!!m_location) && m_location.executableAddress() != JITWriteBarrierFlag) || (location.executableAddress() == m_location.executableAddress()));
85        MacroAssembler::repatchPointer(m_location, value);
86        ASSERT(get() == value);
87    }
88
89    JSCell* get() const
90    {
91        if (!m_location || m_location.executableAddress() == JITWriteBarrierFlag)
92            return 0;
93        void* result = static_cast<JSCell*>(MacroAssembler::readPointer(m_location));
94        if (result == reinterpret_cast<void*>(unusedPointer))
95            return 0;
96        return static_cast<JSCell*>(result);
97    }
98
99private:
100    void clear(void* clearedValue)
101    {
102        if (!m_location)
103            return;
104        if (m_location.executableAddress() != JITWriteBarrierFlag)
105            MacroAssembler::repatchPointer(m_location, clearedValue);
106    }
107
108    CodeLocationDataLabelPtr m_location;
109};
110
111#undef JITWriteBarrierFlag
112
113template <typename T> class JITWriteBarrier : public JITWriteBarrierBase {
114public:
115    JITWriteBarrier()
116    {
117    }
118
119    void set(VM& vm, CodeLocationDataLabelPtr location, JSCell* owner, T* value)
120    {
121        validateCell(owner);
122        validateCell(value);
123        JITWriteBarrierBase::set(vm, location, owner, value);
124    }
125    void set(VM& vm, JSCell* owner, T* value)
126    {
127        set(vm, location(), owner, value);
128    }
129    T* get() const
130    {
131        T* result = static_cast<T*>(JITWriteBarrierBase::get());
132        if (result)
133            validateCell(result);
134        return result;
135    }
136};
137
138template<typename T> inline void SlotVisitor::append(JITWriteBarrier<T>* slot)
139{
140    internalAppend(0, slot->get());
141}
142
143}
144
145#endif // ENABLE(JIT)
146
147#endif
148