Watchpoint.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. #ifndef Watchpoint_h
  26. #define Watchpoint_h
  27. #include <wtf/RefCounted.h>
  28. #include <wtf/SentinelLinkedList.h>
  29. namespace JSC {
  30. #if ENABLE(DETACHED_JIT)
  31. class Watchpoint : public BasicRawSentinelNode<Watchpoint> {
  32. friend class StructureStubClearingWatchpoint;
  33. friend class JumpReplacementWatchpoint;
  34. public:
  35. typedef enum {
  36. e_StrutureStubClearingType,
  37. e_JumpReplacementType,
  38. } WatchpointType;
  39. Watchpoint(WatchpointType type)
  40. : m_type(type)
  41. {
  42. }
  43. protected:
  44. ~Watchpoint();
  45. public:
  46. void fire();
  47. private:
  48. WatchpointType m_type;
  49. };
  50. #else
  51. class Watchpoint : public BasicRawSentinelNode<Watchpoint> {
  52. public:
  53. Watchpoint()
  54. {
  55. }
  56. virtual ~Watchpoint();
  57. void fire() { fireInternal(); }
  58. protected:
  59. virtual void fireInternal() = 0;
  60. };
  61. #endif
  62. enum InitialWatchpointSetMode { InitializedWatching, InitializedBlind };
  63. class InlineWatchpointSet;
  64. class WatchpointSet : public RefCounted_shared<WatchpointSet> {
  65. public:
  66. WatchpointSet(InitialWatchpointSetMode);
  67. ~WatchpointSet();
  68. bool isStillValid() const { return !m_isInvalidated; }
  69. bool hasBeenInvalidated() const { return m_isInvalidated; }
  70. // As a convenience, this will ignore 0. That's because code paths in the DFG
  71. // that create speculation watchpoints may choose to bail out if speculation
  72. // had already been terminated.
  73. void add(Watchpoint*);
  74. // Force the watchpoint set to behave as if it was being watched even if no
  75. // watchpoints have been installed. This will result in invalidation if the
  76. // watchpoint would have fired. That's a pretty good indication that you
  77. // probably don't want to set watchpoints, since we typically don't want to
  78. // set watchpoints that we believe will actually be fired.
  79. void startWatching() { m_isWatched = true; }
  80. void notifyWrite()
  81. {
  82. if (!m_isWatched)
  83. return;
  84. notifyWriteSlow();
  85. }
  86. bool* addressOfIsWatched() { return &m_isWatched; }
  87. JS_EXPORT_PRIVATE void notifyWriteSlow(); // Call only if you've checked isWatched.
  88. private:
  89. void fireAllWatchpoints();
  90. friend class InlineWatchpointSet;
  91. SentinelLinkedList<Watchpoint, BasicRawSentinelNode<Watchpoint> > m_set;
  92. bool m_isWatched;
  93. bool m_isInvalidated;
  94. };
  95. // InlineWatchpointSet is a low-overhead, non-copyable watchpoint set in which
  96. // it is not possible to quickly query whether it is being watched in a single
  97. // branch. There is a fairly simple tradeoff between WatchpointSet and
  98. // InlineWatchpointSet:
  99. //
  100. // Do you have to emit JIT code that rapidly tests whether the watchpoint set
  101. // is being watched? If so, use WatchpointSet.
  102. //
  103. // Do you need multiple parties to have pointers to the same WatchpointSet?
  104. // If so, use WatchpointSet.
  105. //
  106. // Do you have to allocate a lot of watchpoint sets? If so, use
  107. // InlineWatchpointSet unless you answered "yes" to the previous questions.
  108. //
  109. // InlineWatchpointSet will use just one pointer-width word of memory unless
  110. // you actually add watchpoints to it, in which case it internally inflates
  111. // to a pointer to a WatchpointSet, and transfers its state to the
  112. // WatchpointSet.
  113. class InlineWatchpointSet {
  114. WTF_MAKE_NONCOPYABLE(InlineWatchpointSet);
  115. public:
  116. InlineWatchpointSet(InitialWatchpointSetMode mode)
  117. : m_data((mode == InitializedWatching ? IsWatchedFlag : 0) | IsThinFlag)
  118. {
  119. }
  120. ~InlineWatchpointSet()
  121. {
  122. if (isThin())
  123. return;
  124. freeFat();
  125. }
  126. bool hasBeenInvalidated() const
  127. {
  128. if (isFat())
  129. return fat()->hasBeenInvalidated();
  130. return m_data & IsInvalidatedFlag;
  131. }
  132. bool isStillValid() const
  133. {
  134. return !hasBeenInvalidated();
  135. }
  136. void add(Watchpoint*);
  137. void startWatching()
  138. {
  139. if (isFat()) {
  140. fat()->startWatching();
  141. return;
  142. }
  143. m_data |= IsWatchedFlag;
  144. }
  145. void notifyWrite()
  146. {
  147. if (isFat()) {
  148. fat()->notifyWrite();
  149. return;
  150. }
  151. if (!(m_data & IsWatchedFlag))
  152. return;
  153. m_data |= IsInvalidatedFlag;
  154. }
  155. private:
  156. static const uintptr_t IsThinFlag = 1;
  157. static const uintptr_t IsInvalidatedFlag = 2;
  158. static const uintptr_t IsWatchedFlag = 4;
  159. bool isThin() const { return m_data & IsThinFlag; }
  160. bool isFat() const { return !isThin(); };
  161. WatchpointSet* fat()
  162. {
  163. ASSERT(isFat());
  164. return bitwise_cast<WatchpointSet*>(m_data);
  165. }
  166. const WatchpointSet* fat() const
  167. {
  168. ASSERT(isFat());
  169. return bitwise_cast<WatchpointSet*>(m_data);
  170. }
  171. WatchpointSet* inflate()
  172. {
  173. if (LIKELY(isFat()))
  174. return fat();
  175. return inflateSlow();
  176. }
  177. JS_EXPORT_PRIVATE WatchpointSet* inflateSlow();
  178. JS_EXPORT_PRIVATE void freeFat();
  179. uintptr_t m_data;
  180. };
  181. } // namespace JSC
  182. #endif // Watchpoint_h