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