77fba3efa9a5a45791b2b3ece232bf1d221a706b
[WebKit-https.git] / Source / JavaScriptCore / bytecode / Watchpoint.h
1 /*
2  * Copyright (C) 2012-2016 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 #pragma once
27
28 #include <wtf/Atomics.h>
29 #include <wtf/FastMalloc.h>
30 #include <wtf/Noncopyable.h>
31 #include <wtf/Nonmovable.h>
32 #include <wtf/PrintStream.h>
33 #include <wtf/ScopedLambda.h>
34 #include <wtf/SentinelLinkedList.h>
35 #include <wtf/ThreadSafeRefCounted.h>
36
37 namespace JSC {
38
39 class VM;
40
41 class FireDetail {
42     void* operator new(size_t) = delete;
43     
44 public:
45     FireDetail()
46     {
47     }
48     
49     virtual ~FireDetail()
50     {
51     }
52     
53     virtual void dump(PrintStream&) const = 0;
54 };
55
56 class StringFireDetail : public FireDetail {
57 public:
58     StringFireDetail(const char* string)
59         : m_string(string)
60     {
61     }
62     
63     void dump(PrintStream& out) const override;
64
65 private:
66     const char* m_string;
67 };
68
69 template<typename... Types>
70 class LazyFireDetail : public FireDetail {
71 public:
72     LazyFireDetail(const Types&... args)
73     {
74         m_lambda = scopedLambda<void(PrintStream&)>([&] (PrintStream& out) {
75             out.print(args...);
76         });
77     }
78
79     void dump(PrintStream& out) const override { m_lambda(out); }
80
81 private:
82     ScopedLambda<void(PrintStream&)> m_lambda;
83 };
84
85 template<typename... Types>
86 LazyFireDetail<Types...> createLazyFireDetail(const Types&... types)
87 {
88     return LazyFireDetail<Types...>(types...);
89 }
90
91 class WatchpointSet;
92
93 class Watchpoint : public BasicRawSentinelNode<Watchpoint> {
94     WTF_MAKE_NONCOPYABLE(Watchpoint);
95     WTF_MAKE_NONMOVABLE(Watchpoint);
96     WTF_MAKE_FAST_ALLOCATED;
97 public:
98     Watchpoint() = default;
99     
100     virtual ~Watchpoint();
101
102 protected:
103     virtual void fireInternal(VM&, const FireDetail&) = 0;
104
105 private:
106     friend class WatchpointSet;
107     void fire(VM&, const FireDetail&);
108 };
109
110 enum WatchpointState {
111     ClearWatchpoint,
112     IsWatched,
113     IsInvalidated
114 };
115
116 class InlineWatchpointSet;
117 class DeferredWatchpointFire;
118 class VM;
119
120 class WatchpointSet : public ThreadSafeRefCounted<WatchpointSet> {
121     friend class LLIntOffsetsExtractor;
122     friend class DeferredWatchpointFire;
123 public:
124     JS_EXPORT_PRIVATE WatchpointSet(WatchpointState);
125     
126     // FIXME: In many cases, it would be amazing if this *did* fire the watchpoints. I suspect that
127     // this might be hard to get right, but still, it might be awesome.
128     JS_EXPORT_PRIVATE ~WatchpointSet(); // Note that this will not fire any of the watchpoints; if you need to know when a WatchpointSet dies then you need a separate mechanism for this.
129
130     static Ref<WatchpointSet> create(WatchpointState state)
131     {
132         return adoptRef(*new WatchpointSet(state));
133     }
134     
135     // Fast way of getting the state, which only works from the main thread.
136     WatchpointState stateOnJSThread() const
137     {
138         return static_cast<WatchpointState>(m_state);
139     }
140     
141     // It is safe to call this from another thread. It may return an old
142     // state. Guarantees that if *first* read the state() of the thing being
143     // watched and it returned IsWatched and *second* you actually read its
144     // value then it's safe to assume that if the state being watched changes
145     // then also the watchpoint state() will change to IsInvalidated.
146     WatchpointState state() const
147     {
148         WTF::loadLoadFence();
149         WatchpointState result = static_cast<WatchpointState>(m_state);
150         WTF::loadLoadFence();
151         return result;
152     }
153     
154     // It is safe to call this from another thread.  It may return true
155     // even if the set actually had been invalidated, but that ought to happen
156     // only in the case of races, and should be rare. Guarantees that if you
157     // call this after observing something that must imply that the set is
158     // invalidated, then you will see this return false. This is ensured by
159     // issuing a load-load fence prior to querying the state.
160     bool isStillValid() const
161     {
162         return state() != IsInvalidated;
163     }
164     // Like isStillValid(), may be called from another thread.
165     bool hasBeenInvalidated() const { return !isStillValid(); }
166     
167     // As a convenience, this will ignore 0. That's because code paths in the DFG
168     // that create speculation watchpoints may choose to bail out if speculation
169     // had already been terminated.
170     void add(Watchpoint*);
171     
172     // Force the watchpoint set to behave as if it was being watched even if no
173     // watchpoints have been installed. This will result in invalidation if the
174     // watchpoint would have fired. That's a pretty good indication that you
175     // probably don't want to set watchpoints, since we typically don't want to
176     // set watchpoints that we believe will actually be fired.
177     void startWatching()
178     {
179         ASSERT(m_state != IsInvalidated);
180         if (m_state == IsWatched)
181             return;
182         WTF::storeStoreFence();
183         m_state = IsWatched;
184         WTF::storeStoreFence();
185     }
186
187     template <typename T>
188     void fireAll(VM& vm, T& fireDetails)
189     {
190         if (LIKELY(m_state != IsWatched))
191             return;
192         fireAllSlow(vm, fireDetails);
193     }
194
195     void touch(VM& vm, const FireDetail& detail)
196     {
197         if (state() == ClearWatchpoint)
198             startWatching();
199         else
200             fireAll(vm, detail);
201     }
202     
203     void touch(VM& vm, const char* reason)
204     {
205         touch(vm, StringFireDetail(reason));
206     }
207     
208     void invalidate(VM& vm, const FireDetail& detail)
209     {
210         if (state() == IsWatched)
211             fireAll(vm, detail);
212         m_state = IsInvalidated;
213     }
214     
215     void invalidate(VM& vm, const char* reason)
216     {
217         invalidate(vm, StringFireDetail(reason));
218     }
219     
220     bool isBeingWatched() const
221     {
222         return m_setIsNotEmpty;
223     }
224     
225     int8_t* addressOfState() { return &m_state; }
226     static ptrdiff_t offsetOfState() { return OBJECT_OFFSETOF(WatchpointSet, m_state); }
227     int8_t* addressOfSetIsNotEmpty() { return &m_setIsNotEmpty; }
228     
229     JS_EXPORT_PRIVATE void fireAllSlow(VM&, const FireDetail&); // Call only if you've checked isWatched.
230     JS_EXPORT_PRIVATE void fireAllSlow(VM&, DeferredWatchpointFire* deferredWatchpoints); // Ditto.
231     JS_EXPORT_PRIVATE void fireAllSlow(VM&, const char* reason); // Ditto.
232     
233 private:
234     void fireAllWatchpoints(VM&, const FireDetail&);
235     void take(WatchpointSet* other);
236     
237     friend class InlineWatchpointSet;
238
239     int8_t m_state;
240     int8_t m_setIsNotEmpty;
241
242     SentinelLinkedList<Watchpoint, BasicRawSentinelNode<Watchpoint>> m_set;
243 };
244
245 // InlineWatchpointSet is a low-overhead, non-copyable watchpoint set in which
246 // it is not possible to quickly query whether it is being watched in a single
247 // branch. There is a fairly simple tradeoff between WatchpointSet and
248 // InlineWatchpointSet:
249 //
250 // Do you have to emit JIT code that rapidly tests whether the watchpoint set
251 // is being watched?  If so, use WatchpointSet.
252 //
253 // Do you need multiple parties to have pointers to the same WatchpointSet?
254 // If so, use WatchpointSet.
255 //
256 // Do you have to allocate a lot of watchpoint sets?  If so, use
257 // InlineWatchpointSet unless you answered "yes" to the previous questions.
258 //
259 // InlineWatchpointSet will use just one pointer-width word of memory unless
260 // you actually add watchpoints to it, in which case it internally inflates
261 // to a pointer to a WatchpointSet, and transfers its state to the
262 // WatchpointSet.
263
264 class InlineWatchpointSet {
265     WTF_MAKE_NONCOPYABLE(InlineWatchpointSet);
266 public:
267     InlineWatchpointSet(WatchpointState state)
268         : m_data(encodeState(state))
269     {
270     }
271     
272     ~InlineWatchpointSet()
273     {
274         if (isThin())
275             return;
276         freeFat();
277     }
278     
279     // Fast way of getting the state, which only works from the main thread.
280     WatchpointState stateOnJSThread() const
281     {
282         uintptr_t data = m_data;
283         if (isFat(data))
284             return fat(data)->stateOnJSThread();
285         return decodeState(data);
286     }
287
288     // It is safe to call this from another thread. It may return a prior state,
289     // but that should be fine since you should only perform actions based on the
290     // state if you also add a watchpoint.
291     WatchpointState state() const
292     {
293         WTF::loadLoadFence();
294         uintptr_t data = m_data;
295         WTF::loadLoadFence();
296         if (isFat(data))
297             return fat(data)->state();
298         return decodeState(data);
299     }
300     
301     // It is safe to call this from another thread.  It may return false
302     // even if the set actually had been invalidated, but that ought to happen
303     // only in the case of races, and should be rare.
304     bool hasBeenInvalidated() const
305     {
306         return state() == IsInvalidated;
307     }
308     
309     // Like hasBeenInvalidated(), may be called from another thread.
310     bool isStillValid() const
311     {
312         return !hasBeenInvalidated();
313     }
314     
315     void add(Watchpoint*);
316     
317     void startWatching()
318     {
319         if (isFat()) {
320             fat()->startWatching();
321             return;
322         }
323         ASSERT(decodeState(m_data) != IsInvalidated);
324         m_data = encodeState(IsWatched);
325     }
326
327     template <typename T>
328     void fireAll(VM& vm, T fireDetails)
329     {
330         if (isFat()) {
331             fat()->fireAll(vm, fireDetails);
332             return;
333         }
334         if (decodeState(m_data) == ClearWatchpoint)
335             return;
336         m_data = encodeState(IsInvalidated);
337         WTF::storeStoreFence();
338     }
339
340     void invalidate(VM& vm, const FireDetail& detail)
341     {
342         if (isFat())
343             fat()->invalidate(vm, detail);
344         else
345             m_data = encodeState(IsInvalidated);
346     }
347     
348     JS_EXPORT_PRIVATE void fireAll(VM&, const char* reason);
349     
350     void touch(VM& vm, const FireDetail& detail)
351     {
352         if (isFat()) {
353             fat()->touch(vm, detail);
354             return;
355         }
356         uintptr_t data = m_data;
357         if (decodeState(data) == IsInvalidated)
358             return;
359         WTF::storeStoreFence();
360         if (decodeState(data) == ClearWatchpoint)
361             m_data = encodeState(IsWatched);
362         else
363             m_data = encodeState(IsInvalidated);
364         WTF::storeStoreFence();
365     }
366     
367     void touch(VM& vm, const char* reason)
368     {
369         touch(vm, StringFireDetail(reason));
370     }
371
372     // Note that for any watchpoint that is visible from the DFG, it would be incorrect to write code like:
373     //
374     // if (w.isBeingWatched())
375     //     w.fireAll()
376     //
377     // Concurrently to this, the DFG could do:
378     //
379     // if (w.isStillValid())
380     //     perform optimizations;
381     // if (!w.isStillValid())
382     //     retry compilation;
383     //
384     // Note that the DFG algorithm is widespread, and sound, because fireAll() and invalidate() will leave
385     // the watchpoint in a !isStillValid() state. Hence, if fireAll() or invalidate() interleaved between
386     // the first isStillValid() check and the second one, then it would simply cause the DFG to retry
387     // compilation later.
388     //
389     // But, if you change some piece of state that the DFG might optimize for, but invalidate the
390     // watchpoint by doing:
391     //
392     // if (w.isBeingWatched())
393     //     w.fireAll()
394     //
395     // then the DFG would never know that you invalidated state between the two checks.
396     //
397     // There are two ways to work around this:
398     //
399     // - Call fireAll() without a isBeingWatched() check. Then, the DFG will know that the watchpoint has
400     //   been invalidated when it does its second check.
401     //
402     // - Do not expose the watchpoint set to the DFG directly, and have your own way of validating whether
403     //   the assumptions that the DFG thread used are still valid when the DFG code is installed.
404     bool isBeingWatched() const
405     {
406         if (isFat())
407             return fat()->isBeingWatched();
408         return false;
409     }
410
411     // We expose this because sometimes a client knows its about to start
412     // watching this InlineWatchpointSet, hence it'll become inflated regardless.
413     // Such clients may find it useful to have a WatchpointSet* pointer, for example,
414     // if they collect a Vector of WatchpointSet*.
415     WatchpointSet* inflate()
416     {
417         if (LIKELY(isFat()))
418             return fat();
419         return inflateSlow();
420     }
421     
422 private:
423     static const uintptr_t IsThinFlag        = 1;
424     static const uintptr_t StateMask         = 6;
425     static const uintptr_t StateShift        = 1;
426     
427     static bool isThin(uintptr_t data) { return data & IsThinFlag; }
428     static bool isFat(uintptr_t data) { return !isThin(data); }
429     
430     static WatchpointState decodeState(uintptr_t data)
431     {
432         ASSERT(isThin(data));
433         return static_cast<WatchpointState>((data & StateMask) >> StateShift);
434     }
435     
436     static uintptr_t encodeState(WatchpointState state)
437     {
438         return (static_cast<uintptr_t>(state) << StateShift) | IsThinFlag;
439     }
440     
441     bool isThin() const { return isThin(m_data); }
442     bool isFat() const { return isFat(m_data); };
443     
444     static WatchpointSet* fat(uintptr_t data)
445     {
446         return bitwise_cast<WatchpointSet*>(data);
447     }
448     
449     WatchpointSet* fat()
450     {
451         ASSERT(isFat());
452         return fat(m_data);
453     }
454     
455     const WatchpointSet* fat() const
456     {
457         ASSERT(isFat());
458         return fat(m_data);
459     }
460     
461     JS_EXPORT_PRIVATE WatchpointSet* inflateSlow();
462     JS_EXPORT_PRIVATE void freeFat();
463     
464     uintptr_t m_data;
465 };
466
467 class DeferredWatchpointFire : public FireDetail {
468     WTF_MAKE_NONCOPYABLE(DeferredWatchpointFire);
469 public:
470     JS_EXPORT_PRIVATE DeferredWatchpointFire(VM&);
471     JS_EXPORT_PRIVATE ~DeferredWatchpointFire();
472
473     JS_EXPORT_PRIVATE void takeWatchpointsToFire(WatchpointSet*);
474     JS_EXPORT_PRIVATE void fireAll();
475
476     void dump(PrintStream& out) const override = 0;
477 private:
478     VM& m_vm;
479     WatchpointSet m_watchpointsToFire;
480 };
481
482 } // namespace JSC
483
484 namespace WTF {
485
486 void printInternal(PrintStream& out, JSC::WatchpointState);
487
488 } // namespace WTF
489