OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 15 matching lines...) Expand all Loading... |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 #include "config.h" | 31 #include "config.h" |
32 #include "core/inspector/AsyncCallStackTracker.h" | 32 #include "core/inspector/AsyncCallStackTracker.h" |
33 | 33 |
34 #include "core/dom/ContextLifecycleObserver.h" | 34 #include "core/dom/ContextLifecycleObserver.h" |
35 #include "core/dom/ExecutionContext.h" | 35 #include "core/dom/ExecutionContext.h" |
| 36 #include "core/events/EventTarget.h" |
| 37 #include "core/events/RegisteredEventListener.h" |
| 38 #include "wtf/text/StringBuilder.h" |
36 | 39 |
37 namespace WebCore { | 40 namespace WebCore { |
38 | 41 |
39 class AsyncCallStackTracker::ExecutionContextData : public ContextLifecycleObser
ver { | 42 class AsyncCallStackTracker::ExecutionContextData : public ContextLifecycleObser
ver { |
40 WTF_MAKE_FAST_ALLOCATED; | 43 WTF_MAKE_FAST_ALLOCATED; |
41 public: | 44 public: |
| 45 typedef std::pair<RegisteredEventListener, RefPtr<AsyncCallChain> > EventLis
tenerAsyncCallChain; |
| 46 typedef Vector<EventListenerAsyncCallChain, 1> EventListenerAsyncCallChainVe
ctor; |
| 47 typedef HashMap<AtomicString, EventListenerAsyncCallChainVector> EventListen
erAsyncCallChainVectorHashMap; |
| 48 |
42 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu
tionContext) | 49 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu
tionContext) |
43 : ContextLifecycleObserver(executionContext) | 50 : ContextLifecycleObserver(executionContext) |
44 , m_tracker(tracker) | 51 , m_tracker(tracker) |
45 { | 52 { |
46 } | 53 } |
47 | 54 |
48 virtual void contextDestroyed() OVERRIDE | 55 virtual void contextDestroyed() OVERRIDE |
49 { | 56 { |
50 ASSERT(executionContext()); | 57 ASSERT(executionContext()); |
51 ExecutionContextData* self = m_tracker->m_executionContextDataMap.take(e
xecutionContext()); | 58 ExecutionContextData* self = m_tracker->m_executionContextDataMap.take(e
xecutionContext()); |
52 ASSERT(self == this); | 59 ASSERT(self == this); |
53 ContextLifecycleObserver::contextDestroyed(); | 60 ContextLifecycleObserver::contextDestroyed(); |
54 delete self; | 61 delete self; |
55 } | 62 } |
56 | 63 |
57 private: | 64 void addEventListenerData(EventTarget* eventTarget, const AtomicString& even
tType, const EventListenerAsyncCallChain& item) |
58 friend class AsyncCallStackTracker; | 65 { |
| 66 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap>::iterato
r it = m_eventTargetCallChains.find(eventTarget); |
| 67 if (it == m_eventTargetCallChains.end()) |
| 68 it = m_eventTargetCallChains.set(eventTarget, EventListenerAsyncCall
ChainVectorHashMap()).iterator; |
| 69 EventListenerAsyncCallChainVectorHashMap& map = it->value; |
| 70 EventListenerAsyncCallChainVectorHashMap::iterator it2 = map.find(eventT
ype); |
| 71 if (it2 == map.end()) |
| 72 it2 = map.set(eventType, EventListenerAsyncCallChainVector()).iterat
or; |
| 73 it2->value.append(item); |
| 74 } |
| 75 |
| 76 void removeEventListenerData(EventTarget* eventTarget, const AtomicString& e
ventType, const RegisteredEventListener& item) |
| 77 { |
| 78 findEventListenerData(eventTarget, eventType, item, true); |
| 79 } |
| 80 |
| 81 PassRefPtr<AsyncCallChain> findEventListenerData(EventTarget* eventTarget, c
onst AtomicString& eventType, const RegisteredEventListener& item, bool remove =
false) |
| 82 { |
| 83 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap>::iterato
r it = m_eventTargetCallChains.find(eventTarget); |
| 84 if (it == m_eventTargetCallChains.end()) |
| 85 return 0; |
| 86 EventListenerAsyncCallChainVectorHashMap& map = it->value; |
| 87 EventListenerAsyncCallChainVectorHashMap::iterator it2 = map.find(eventT
ype); |
| 88 if (it2 == map.end()) |
| 89 return 0; |
| 90 RefPtr<AsyncCallChain> result; |
| 91 EventListenerAsyncCallChainVector& vector = it2->value; |
| 92 for (size_t i = 0; i < vector.size(); ++i) { |
| 93 if (vector[i].first == item) { |
| 94 result = vector[i].second; |
| 95 if (remove) { |
| 96 vector.remove(i); |
| 97 if (vector.isEmpty()) |
| 98 map.remove(it2); |
| 99 if (map.isEmpty()) |
| 100 m_eventTargetCallChains.remove(it); |
| 101 } |
| 102 break; |
| 103 } |
| 104 } |
| 105 return result.release(); |
| 106 } |
| 107 |
| 108 public: |
59 AsyncCallStackTracker* m_tracker; | 109 AsyncCallStackTracker* m_tracker; |
60 HashSet<int> m_intervalTimerIds; | 110 HashSet<int> m_intervalTimerIds; |
61 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; | 111 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; |
62 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; | 112 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; |
| 113 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap> m_eventTarge
tCallChains; |
63 }; | 114 }; |
64 | 115 |
65 AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const String& description,
const ScriptValue& callFrames) | 116 AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const String& description,
const ScriptValue& callFrames) |
66 : m_description(description) | 117 : m_description(description) |
67 , m_callFrames(callFrames) | 118 , m_callFrames(callFrames) |
68 { | 119 { |
69 } | 120 } |
70 | 121 |
71 AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack() | 122 AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack() |
72 { | 123 { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 ASSERT(timerId > 0); | 157 ASSERT(timerId > 0); |
107 ExecutionContextData* data = createContextDataIfNeeded(context); | 158 ExecutionContextData* data = createContextDataIfNeeded(context); |
108 data->m_timerCallChains.set(timerId, createAsyncCallChain(singleShot ? setTi
meoutName : setIntervalName, callFrames)); | 159 data->m_timerCallChains.set(timerId, createAsyncCallChain(singleShot ? setTi
meoutName : setIntervalName, callFrames)); |
109 if (!singleShot) | 160 if (!singleShot) |
110 data->m_intervalTimerIds.add(timerId); | 161 data->m_intervalTimerIds.add(timerId); |
111 } | 162 } |
112 | 163 |
113 void AsyncCallStackTracker::didRemoveTimer(ExecutionContext* context, int timerI
d) | 164 void AsyncCallStackTracker::didRemoveTimer(ExecutionContext* context, int timerI
d) |
114 { | 165 { |
115 ASSERT(context); | 166 ASSERT(context); |
116 if (!isEnabled() || timerId <= 0) | 167 ASSERT(isEnabled()); |
| 168 if (timerId <= 0) |
117 return; | 169 return; |
118 ExecutionContextData* data = m_executionContextDataMap.get(context); | 170 ExecutionContextData* data = m_executionContextDataMap.get(context); |
119 if (!data) | 171 if (!data) |
120 return; | 172 return; |
121 data->m_intervalTimerIds.remove(timerId); | 173 data->m_intervalTimerIds.remove(timerId); |
122 data->m_timerCallChains.remove(timerId); | 174 data->m_timerCallChains.remove(timerId); |
123 } | 175 } |
124 | 176 |
125 void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId
) | 177 void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId
) |
126 { | 178 { |
127 ASSERT(context); | 179 ASSERT(context); |
128 if (!isEnabled()) | 180 ASSERT(isEnabled()); |
129 return; | |
130 ASSERT(timerId > 0); | 181 ASSERT(timerId > 0); |
131 ASSERT(!m_currentAsyncCallChain); | 182 ASSERT(!m_currentAsyncCallChain); |
132 ExecutionContextData* data = m_executionContextDataMap.get(context); | 183 ExecutionContextData* data = m_executionContextDataMap.get(context); |
133 if (!data) | 184 if (!data) |
134 return; | 185 return; |
135 if (data->m_intervalTimerIds.contains(timerId)) | 186 if (data->m_intervalTimerIds.contains(timerId)) |
136 m_currentAsyncCallChain = data->m_timerCallChains.get(timerId); | 187 setCurrentAsyncCallChain(data->m_timerCallChains.get(timerId)); |
137 else | 188 else |
138 m_currentAsyncCallChain = data->m_timerCallChains.take(timerId); | 189 setCurrentAsyncCallChain(data->m_timerCallChains.take(timerId)); |
139 } | 190 } |
140 | 191 |
141 void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context,
int callbackId, const ScriptValue& callFrames) | 192 void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context,
int callbackId, const ScriptValue& callFrames) |
142 { | 193 { |
143 DEFINE_STATIC_LOCAL(String, requestAnimationFrameName, ("requestAnimationFra
me")); | 194 DEFINE_STATIC_LOCAL(String, requestAnimationFrameName, ("requestAnimationFra
me")); |
144 | 195 |
145 ASSERT(context); | 196 ASSERT(context); |
146 ASSERT(isEnabled()); | 197 ASSERT(isEnabled()); |
147 if (!validateCallFrames(callFrames)) | 198 if (!validateCallFrames(callFrames)) |
148 return; | 199 return; |
149 ASSERT(callbackId > 0); | 200 ASSERT(callbackId > 0); |
150 ExecutionContextData* data = createContextDataIfNeeded(context); | 201 ExecutionContextData* data = createContextDataIfNeeded(context); |
151 data->m_animationFrameCallChains.set(callbackId, createAsyncCallChain(reques
tAnimationFrameName, callFrames)); | 202 data->m_animationFrameCallChains.set(callbackId, createAsyncCallChain(reques
tAnimationFrameName, callFrames)); |
152 } | 203 } |
153 | 204 |
154 void AsyncCallStackTracker::didCancelAnimationFrame(ExecutionContext* context, i
nt callbackId) | 205 void AsyncCallStackTracker::didCancelAnimationFrame(ExecutionContext* context, i
nt callbackId) |
155 { | 206 { |
156 ASSERT(context); | 207 ASSERT(context); |
157 if (!isEnabled() || callbackId <= 0) | 208 ASSERT(isEnabled()); |
| 209 if (callbackId <= 0) |
158 return; | 210 return; |
159 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 211 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
160 data->m_animationFrameCallChains.remove(callbackId); | 212 data->m_animationFrameCallChains.remove(callbackId); |
161 } | 213 } |
162 | 214 |
163 void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in
t callbackId) | 215 void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in
t callbackId) |
164 { | 216 { |
165 ASSERT(context); | 217 ASSERT(context); |
166 if (!isEnabled()) | 218 ASSERT(isEnabled()); |
167 return; | |
168 ASSERT(callbackId > 0); | 219 ASSERT(callbackId > 0); |
169 ASSERT(!m_currentAsyncCallChain); | 220 ASSERT(!m_currentAsyncCallChain); |
170 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 221 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
171 m_currentAsyncCallChain = data->m_animationFrameCallChains.take(callback
Id); | 222 setCurrentAsyncCallChain(data->m_animationFrameCallChains.take(callbackI
d)); |
| 223 } |
| 224 |
| 225 void AsyncCallStackTracker::didAddEventListener(EventTarget* eventTarget, const
AtomicString& eventType, EventListener* listener, bool useCapture, const ScriptV
alue& callFrames) |
| 226 { |
| 227 ASSERT(eventTarget->executionContext()); |
| 228 ASSERT(isEnabled()); |
| 229 if (!validateCallFrames(callFrames)) |
| 230 return; |
| 231 |
| 232 StringBuilder description; |
| 233 description.append(eventTarget->interfaceName()); |
| 234 if (!description.isEmpty()) |
| 235 description.append("."); |
| 236 if (listener->isAttribute()) { |
| 237 description.append("on"); |
| 238 description.append(eventType); |
| 239 } else { |
| 240 description.append("addEventListener(\""); |
| 241 description.append(eventType); |
| 242 description.append("\")"); |
| 243 } |
| 244 |
| 245 ExecutionContextData* data = createContextDataIfNeeded(eventTarget->executio
nContext()); |
| 246 data->addEventListenerData(eventTarget, eventType, std::make_pair(Registered
EventListener(listener, useCapture), createAsyncCallChain(description.toString()
, callFrames))); |
| 247 } |
| 248 |
| 249 void AsyncCallStackTracker::didRemoveEventListener(EventTarget* eventTarget, con
st AtomicString& eventType, EventListener* listener, bool useCapture) |
| 250 { |
| 251 ASSERT(eventTarget->executionContext()); |
| 252 ASSERT(isEnabled()); |
| 253 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) |
| 254 data->removeEventListenerData(eventTarget, eventType, RegisteredEventLis
tener(listener, useCapture)); |
| 255 } |
| 256 |
| 257 void AsyncCallStackTracker::didRemoveAllEventListeners(EventTarget* eventTarget) |
| 258 { |
| 259 ASSERT(eventTarget->executionContext()); |
| 260 ASSERT(isEnabled()); |
| 261 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) |
| 262 data->m_eventTargetCallChains.remove(eventTarget); |
| 263 } |
| 264 |
| 265 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom
icString& eventType, EventListener* listener, bool useCapture) |
| 266 { |
| 267 ASSERT(eventTarget->executionContext()); |
| 268 ASSERT(isEnabled()); |
| 269 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) |
| 270 setCurrentAsyncCallChain(data->findEventListenerData(eventTarget, eventT
ype, RegisteredEventListener(listener, useCapture))); |
172 } | 271 } |
173 | 272 |
174 void AsyncCallStackTracker::didFireAsyncCall() | 273 void AsyncCallStackTracker::didFireAsyncCall() |
175 { | 274 { |
176 m_currentAsyncCallChain = 0; | 275 setCurrentAsyncCallChain(0); |
177 } | 276 } |
178 | 277 |
179 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA
syncCallChain(const String& description, const ScriptValue& callFrames) | 278 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA
syncCallChain(const String& description, const ScriptValue& callFrames) |
180 { | 279 { |
181 ASSERT(isEnabled()); | |
182 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC
allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr
acker::AsyncCallChain()); | 280 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC
allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr
acker::AsyncCallChain()); |
183 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); | 281 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); |
184 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta
ck(description, callFrames))); | 282 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta
ck(description, callFrames))); |
185 return chain.release(); | 283 return chain.release(); |
186 } | 284 } |
187 | 285 |
| 286 void AsyncCallStackTracker::setCurrentAsyncCallChain(PassRefPtr<AsyncCallChain>
chain) |
| 287 { |
| 288 if (m_currentAsyncCallChain) { |
| 289 m_nestedAsyncCallCount += chain ? 1 : -1; |
| 290 if (!m_nestedAsyncCallCount) |
| 291 m_currentAsyncCallChain = 0; |
| 292 } else if (chain) { |
| 293 m_currentAsyncCallChain = chain; |
| 294 m_nestedAsyncCallCount = 1; |
| 295 } |
| 296 } |
| 297 |
188 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain,
unsigned maxDepth) | 298 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain,
unsigned maxDepth) |
189 { | 299 { |
190 while (chain->m_callStacks.size() > maxDepth) | 300 while (chain->m_callStacks.size() > maxDepth) |
191 chain->m_callStacks.removeLast(); | 301 chain->m_callStacks.removeLast(); |
192 } | 302 } |
193 | 303 |
194 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) | 304 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) |
195 { | 305 { |
196 return !callFrames.hasNoValue(); | 306 return !callFrames.hasNoValue(); |
197 } | 307 } |
198 | 308 |
199 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex
tDataIfNeeded(ExecutionContext* context) | 309 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex
tDataIfNeeded(ExecutionContext* context) |
200 { | 310 { |
201 ExecutionContextData* data = m_executionContextDataMap.get(context); | 311 ExecutionContextData* data = m_executionContextDataMap.get(context); |
202 if (!data) { | 312 if (!data) { |
203 data = new AsyncCallStackTracker::ExecutionContextData(this, context); | 313 data = new AsyncCallStackTracker::ExecutionContextData(this, context); |
204 m_executionContextDataMap.set(context, data); | 314 m_executionContextDataMap.set(context, data); |
205 } | 315 } |
206 return data; | 316 return data; |
207 } | 317 } |
208 | 318 |
209 void AsyncCallStackTracker::clear() | 319 void AsyncCallStackTracker::clear() |
210 { | 320 { |
211 m_currentAsyncCallChain = 0; | 321 m_currentAsyncCallChain = 0; |
| 322 m_nestedAsyncCallCount = 0; |
212 ExecutionContextDataMap copy; | 323 ExecutionContextDataMap copy; |
213 m_executionContextDataMap.swap(copy); | 324 m_executionContextDataMap.swap(copy); |
214 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e
nd(); ++it) | 325 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e
nd(); ++it) |
215 delete it->value; | 326 delete it->value; |
216 } | 327 } |
217 | 328 |
218 } // namespace WebCore | 329 } // namespace WebCore |
OLD | NEW |