]> git.saurik.com Git - apple/javascriptcore.git/blame - bytecode/Watchpoint.h
JavaScriptCore-1218.35.tar.gz
[apple/javascriptcore.git] / bytecode / Watchpoint.h
CommitLineData
93a37866
A
1/*
2 * Copyright (C) 2012 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef Watchpoint_h
27#define Watchpoint_h
28
29#include <wtf/RefCounted.h>
30#include <wtf/SentinelLinkedList.h>
31
32namespace JSC {
33
34class Watchpoint : public BasicRawSentinelNode<Watchpoint> {
35public:
36 Watchpoint()
37 {
38 }
39
40 virtual ~Watchpoint();
41
42 void fire() { fireInternal(); }
43
44protected:
45 virtual void fireInternal() = 0;
46};
47
48enum InitialWatchpointSetMode { InitializedWatching, InitializedBlind };
49
50class InlineWatchpointSet;
51
52class WatchpointSet : public RefCounted<WatchpointSet> {
53public:
54 WatchpointSet(InitialWatchpointSetMode);
55 ~WatchpointSet();
56
57 bool isStillValid() const { return !m_isInvalidated; }
58 bool hasBeenInvalidated() const { return m_isInvalidated; }
59
60 // As a convenience, this will ignore 0. That's because code paths in the DFG
61 // that create speculation watchpoints may choose to bail out if speculation
62 // had already been terminated.
63 void add(Watchpoint*);
64
65 // Force the watchpoint set to behave as if it was being watched even if no
66 // watchpoints have been installed. This will result in invalidation if the
67 // watchpoint would have fired. That's a pretty good indication that you
68 // probably don't want to set watchpoints, since we typically don't want to
69 // set watchpoints that we believe will actually be fired.
70 void startWatching() { m_isWatched = true; }
71
72 void notifyWrite()
73 {
74 if (!m_isWatched)
75 return;
76 notifyWriteSlow();
77 }
78
79 bool* addressOfIsWatched() { return &m_isWatched; }
80
81 JS_EXPORT_PRIVATE void notifyWriteSlow(); // Call only if you've checked isWatched.
82
83private:
84 void fireAllWatchpoints();
85
86 friend class InlineWatchpointSet;
87
88 SentinelLinkedList<Watchpoint, BasicRawSentinelNode<Watchpoint> > m_set;
89 bool m_isWatched;
90 bool m_isInvalidated;
91};
92
93// InlineWatchpointSet is a low-overhead, non-copyable watchpoint set in which
94// it is not possible to quickly query whether it is being watched in a single
95// branch. There is a fairly simple tradeoff between WatchpointSet and
96// InlineWatchpointSet:
97//
98// Do you have to emit JIT code that rapidly tests whether the watchpoint set
99// is being watched? If so, use WatchpointSet.
100//
101// Do you need multiple parties to have pointers to the same WatchpointSet?
102// If so, use WatchpointSet.
103//
104// Do you have to allocate a lot of watchpoint sets? If so, use
105// InlineWatchpointSet unless you answered "yes" to the previous questions.
106//
107// InlineWatchpointSet will use just one pointer-width word of memory unless
108// you actually add watchpoints to it, in which case it internally inflates
109// to a pointer to a WatchpointSet, and transfers its state to the
110// WatchpointSet.
111
112class InlineWatchpointSet {
113 WTF_MAKE_NONCOPYABLE(InlineWatchpointSet);
114public:
115 InlineWatchpointSet(InitialWatchpointSetMode mode)
116 : m_data((mode == InitializedWatching ? IsWatchedFlag : 0) | IsThinFlag)
117 {
118 }
119
120 ~InlineWatchpointSet()
121 {
122 if (isThin())
123 return;
124 freeFat();
125 }
126
127 bool hasBeenInvalidated() const
128 {
129 if (isFat())
130 return fat()->hasBeenInvalidated();
131 return m_data & IsInvalidatedFlag;
132 }
133
134 bool isStillValid() const
135 {
136 return !hasBeenInvalidated();
137 }
138
139 void add(Watchpoint*);
140
141 void startWatching()
142 {
143 if (isFat()) {
144 fat()->startWatching();
145 return;
146 }
147 m_data |= IsWatchedFlag;
148 }
149
150 void notifyWrite()
151 {
152 if (isFat()) {
153 fat()->notifyWrite();
154 return;
155 }
156 if (!(m_data & IsWatchedFlag))
157 return;
158 m_data |= IsInvalidatedFlag;
159 }
160
161private:
162 static const uintptr_t IsThinFlag = 1;
163 static const uintptr_t IsInvalidatedFlag = 2;
164 static const uintptr_t IsWatchedFlag = 4;
165
166 bool isThin() const { return m_data & IsThinFlag; }
167 bool isFat() const { return !isThin(); };
168
169 WatchpointSet* fat()
170 {
171 ASSERT(isFat());
172 return bitwise_cast<WatchpointSet*>(m_data);
173 }
174
175 const WatchpointSet* fat() const
176 {
177 ASSERT(isFat());
178 return bitwise_cast<WatchpointSet*>(m_data);
179 }
180
181 WatchpointSet* inflate()
182 {
183 if (LIKELY(isFat()))
184 return fat();
185 return inflateSlow();
186 }
187
188 JS_EXPORT_PRIVATE WatchpointSet* inflateSlow();
189 JS_EXPORT_PRIVATE void freeFat();
190
191 uintptr_t m_data;
192};
193
194} // namespace JSC
195
196#endif // Watchpoint_h
197