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