3d70df42aa33cb369364d93fdb4a2468f33cc30c
[WebKit-https.git] / Source / JavaScriptCore / bytecode / Watchpoint.cpp
1 /*
2  * Copyright (C) 2012-2015 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 #include "config.h"
27 #include "Watchpoint.h"
28
29 #include "AdaptiveInferredPropertyValueWatchpointBase.h"
30 #include "CodeBlockJettisoningWatchpoint.h"
31 #include "DFGAdaptiveStructureWatchpoint.h"
32 #include "FunctionRareData.h"
33 #include "HeapInlines.h"
34 #include "LLIntPrototypeLoadAdaptiveStructureWatchpoint.h"
35 #include "ObjectToStringAdaptiveStructureWatchpoint.h"
36 #include "StructureStubClearingWatchpoint.h"
37 #include "VM.h"
38 #include <wtf/CompilationThread.h>
39
40 namespace JSC {
41
42 void StringFireDetail::dump(PrintStream& out) const
43 {
44     out.print(m_string);
45 }
46
47 Watchpoint::~Watchpoint()
48 {
49     if (isOnList()) {
50         // This will happen if we get destroyed before the set fires. That's totally a valid
51         // possibility. For example:
52         //
53         // CodeBlock has a Watchpoint on transition from structure S1. The transition never
54         // happens, but the CodeBlock gets destroyed because of GC.
55         remove();
56     }
57 }
58
59 void Watchpoint::fire(VM& vm, const FireDetail& detail)
60 {
61     RELEASE_ASSERT(!isOnList());
62     switch (m_type) {
63 #define JSC_DEFINE_WATCHPOINT_DISPATCH(type, cast) \
64     case Type::type: \
65         static_cast<cast*>(this)->fireInternal(vm, detail); \
66         break;
67     JSC_WATCHPOINT_TYPES(JSC_DEFINE_WATCHPOINT_DISPATCH)
68 #undef JSC_DEFINE_WATCHPOINT_DISPATCH
69     }
70 }
71
72 WatchpointSet::WatchpointSet(WatchpointState state)
73     : m_state(state)
74     , m_setIsNotEmpty(false)
75 {
76 }
77
78 WatchpointSet::~WatchpointSet()
79 {
80     // Remove all watchpoints, so that they don't try to remove themselves. Note that we
81     // don't fire watchpoints on deletion. We assume that any code that is interested in
82     // watchpoints already also separately has a mechanism to make sure that the code is
83     // either keeping the watchpoint set's owner alive, or does some weak reference thing.
84     while (!m_set.isEmpty())
85         m_set.begin()->remove();
86 }
87
88 void WatchpointSet::add(Watchpoint* watchpoint)
89 {
90     ASSERT(!isCompilationThread());
91     ASSERT(state() != IsInvalidated);
92     if (!watchpoint)
93         return;
94     m_set.push(watchpoint);
95     m_setIsNotEmpty = true;
96     m_state = IsWatched;
97 }
98
99 void WatchpointSet::fireAllSlow(VM& vm, const FireDetail& detail)
100 {
101     ASSERT(state() == IsWatched);
102     
103     WTF::storeStoreFence();
104     m_state = IsInvalidated; // Do this first. Needed for adaptive watchpoints.
105     fireAllWatchpoints(vm, detail);
106     WTF::storeStoreFence();
107 }
108
109 void WatchpointSet::fireAllSlow(VM&, DeferredWatchpointFire* deferredWatchpoints)
110 {
111     ASSERT(state() == IsWatched);
112
113     WTF::storeStoreFence();
114     deferredWatchpoints->takeWatchpointsToFire(this);
115     m_state = IsInvalidated; // Do after moving watchpoints to deferredWatchpoints so deferredWatchpoints gets our current state.
116     WTF::storeStoreFence();
117 }
118
119 void WatchpointSet::fireAllSlow(VM& vm, const char* reason)
120 {
121     fireAllSlow(vm, StringFireDetail(reason));
122 }
123
124 void WatchpointSet::fireAllWatchpoints(VM& vm, const FireDetail& detail)
125 {
126     // In case there are any adaptive watchpoints, we need to make sure that they see that this
127     // watchpoint has been already invalidated.
128     RELEASE_ASSERT(hasBeenInvalidated());
129
130     // Firing a watchpoint may cause a GC to happen. This GC could destroy various
131     // Watchpoints themselves while they're in the process of firing. It's not safe
132     // for most Watchpoints to be destructed while they're in the middle of firing.
133     // This GC could also destroy us, and we're not in a safe state to be destroyed.
134     // The safest thing to do is to DeferGCForAWhile to prevent this GC from happening.
135     DeferGCForAWhile deferGC(vm.heap);
136     
137     while (!m_set.isEmpty()) {
138         Watchpoint* watchpoint = m_set.begin();
139         ASSERT(watchpoint->isOnList());
140         
141         // Removing the Watchpoint before firing it makes it possible to implement watchpoints
142         // that add themselves to a different set when they fire. This kind of "adaptive"
143         // watchpoint can be used to track some semantic property that is more fine-graiend than
144         // what the set can convey. For example, we might care if a singleton object ever has a
145         // property called "foo". We can watch for this by checking if its Structure has "foo" and
146         // then watching its transitions. But then the watchpoint fires if any property is added.
147         // So, before the watchpoint decides to invalidate any code, it can check if it is
148         // possible to add itself to the transition watchpoint set of the singleton object's new
149         // Structure.
150         watchpoint->remove();
151         ASSERT(m_set.begin() != watchpoint);
152         ASSERT(!watchpoint->isOnList());
153         
154         watchpoint->fire(vm, detail);
155         // After we fire the watchpoint, the watchpoint pointer may be a dangling pointer. That's
156         // fine, because we have no use for the pointer anymore.
157     }
158 }
159
160 void WatchpointSet::take(WatchpointSet* other)
161 {
162     ASSERT(state() == ClearWatchpoint);
163     m_set.takeFrom(other->m_set);
164     m_setIsNotEmpty = other->m_setIsNotEmpty;
165     m_state = other->m_state;
166     other->m_setIsNotEmpty = false;
167 }
168
169 void InlineWatchpointSet::add(Watchpoint* watchpoint)
170 {
171     inflate()->add(watchpoint);
172 }
173
174 void InlineWatchpointSet::fireAll(VM& vm, const char* reason)
175 {
176     fireAll(vm, StringFireDetail(reason));
177 }
178
179 WatchpointSet* InlineWatchpointSet::inflateSlow()
180 {
181     ASSERT(isThin());
182     ASSERT(!isCompilationThread());
183     WatchpointSet* fat = adoptRef(new WatchpointSet(decodeState(m_data))).leakRef();
184     WTF::storeStoreFence();
185     m_data = bitwise_cast<uintptr_t>(fat);
186     return fat;
187 }
188
189 void InlineWatchpointSet::freeFat()
190 {
191     ASSERT(isFat());
192     fat()->deref();
193 }
194
195 DeferredWatchpointFire::DeferredWatchpointFire(VM& vm)
196     : m_vm(vm)
197     , m_watchpointsToFire(ClearWatchpoint)
198 {
199 }
200
201 DeferredWatchpointFire::~DeferredWatchpointFire()
202 {
203 }
204
205 void DeferredWatchpointFire::fireAll()
206 {
207     if (m_watchpointsToFire.state() == IsWatched)
208         m_watchpointsToFire.fireAll(m_vm, *this);
209 }
210
211 void DeferredWatchpointFire::takeWatchpointsToFire(WatchpointSet* watchpointsToFire)
212 {
213     ASSERT(m_watchpointsToFire.state() == ClearWatchpoint);
214     ASSERT(watchpointsToFire->state() == IsWatched);
215     m_watchpointsToFire.take(watchpointsToFire);
216 }
217
218 } // namespace JSC
219
220 namespace WTF {
221
222 void printInternal(PrintStream& out, JSC::WatchpointState state)
223 {
224     switch (state) {
225     case JSC::ClearWatchpoint:
226         out.print("ClearWatchpoint");
227         return;
228     case JSC::IsWatched:
229         out.print("IsWatched");
230         return;
231     case JSC::IsInvalidated:
232         out.print("IsInvalidated");
233         return;
234     }
235     RELEASE_ASSERT_NOT_REACHED();
236 }
237
238 } // namespace WTF
239