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 17 matching lines...) Expand all Loading... | |
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" | 36 #include "core/events/EventTarget.h" |
37 #include "core/events/RegisteredEventListener.h" | 37 #include "core/events/RegisteredEventListener.h" |
38 #include "core/xml/XMLHttpRequest.h" | |
39 #include "core/xml/XMLHttpRequestUpload.h" | |
40 #include "wtf/text/AtomicStringHash.h" | |
38 #include "wtf/text/StringBuilder.h" | 41 #include "wtf/text/StringBuilder.h" |
39 | 42 |
40 namespace WebCore { | 43 namespace WebCore { |
41 | 44 |
42 class AsyncCallStackTracker::ExecutionContextData : public ContextLifecycleObser ver { | 45 class AsyncCallStackTracker::ExecutionContextData : public ContextLifecycleObser ver { |
43 WTF_MAKE_FAST_ALLOCATED; | 46 WTF_MAKE_FAST_ALLOCATED; |
44 public: | 47 public: |
45 typedef std::pair<RegisteredEventListener, RefPtr<AsyncCallChain> > EventLis tenerAsyncCallChain; | 48 typedef std::pair<RegisteredEventListener, RefPtr<AsyncCallChain> > EventLis tenerAsyncCallChain; |
46 typedef Vector<EventListenerAsyncCallChain, 1> EventListenerAsyncCallChainVe ctor; | 49 typedef Vector<EventListenerAsyncCallChain, 1> EventListenerAsyncCallChainVe ctor; |
47 typedef HashMap<AtomicString, EventListenerAsyncCallChainVector> EventListen erAsyncCallChainVectorHashMap; | 50 typedef HashMap<AtomicString, EventListenerAsyncCallChainVector> EventListen erAsyncCallChainVectorHashMap; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
104 } | 107 } |
105 return result.release(); | 108 return result.release(); |
106 } | 109 } |
107 | 110 |
108 public: | 111 public: |
109 AsyncCallStackTracker* m_tracker; | 112 AsyncCallStackTracker* m_tracker; |
110 HashSet<int> m_intervalTimerIds; | 113 HashSet<int> m_intervalTimerIds; |
111 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; | 114 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; |
112 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; | 115 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; |
113 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap> m_eventTarge tCallChains; | 116 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap> m_eventTarge tCallChains; |
117 HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; | |
114 }; | 118 }; |
115 | 119 |
120 static XMLHttpRequest* xmlHttpRequestFor(EventTarget* eventTarget) | |
yurys
2013/12/23 09:11:57
toXmlHttpRequest ?
aandrey
2013/12/23 12:09:38
Done.
| |
121 { | |
122 const AtomicString& interfaceName = eventTarget->interfaceName(); | |
123 if (interfaceName == EventTargetNames::XMLHttpRequest) | |
124 return static_cast<XMLHttpRequest*>(eventTarget); | |
125 if (interfaceName == EventTargetNames::XMLHttpRequestUpload) | |
126 return static_cast<XMLHttpRequestUpload*>(eventTarget)->xmlHttpRequest() ; | |
127 return 0; | |
128 } | |
129 | |
116 AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const String& description, const ScriptValue& callFrames) | 130 AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const String& description, const ScriptValue& callFrames) |
117 : m_description(description) | 131 : m_description(description) |
118 , m_callFrames(callFrames) | 132 , m_callFrames(callFrames) |
119 { | 133 { |
120 } | 134 } |
121 | 135 |
122 AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack() | 136 AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack() |
123 { | 137 { |
124 } | 138 } |
125 | 139 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 data->m_intervalTimerIds.remove(timerId); | 187 data->m_intervalTimerIds.remove(timerId); |
174 data->m_timerCallChains.remove(timerId); | 188 data->m_timerCallChains.remove(timerId); |
175 } | 189 } |
176 | 190 |
177 void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId ) | 191 void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId ) |
178 { | 192 { |
179 ASSERT(context); | 193 ASSERT(context); |
180 ASSERT(isEnabled()); | 194 ASSERT(isEnabled()); |
181 ASSERT(timerId > 0); | 195 ASSERT(timerId > 0); |
182 ASSERT(!m_currentAsyncCallChain); | 196 ASSERT(!m_currentAsyncCallChain); |
183 ExecutionContextData* data = m_executionContextDataMap.get(context); | 197 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) { |
184 if (!data) | 198 if (data->m_intervalTimerIds.contains(timerId)) |
185 return; | 199 setCurrentAsyncCallChain(data->m_timerCallChains.get(timerId)); |
186 if (data->m_intervalTimerIds.contains(timerId)) | 200 else |
187 setCurrentAsyncCallChain(data->m_timerCallChains.get(timerId)); | 201 setCurrentAsyncCallChain(data->m_timerCallChains.take(timerId)); |
188 else | 202 } else { |
189 setCurrentAsyncCallChain(data->m_timerCallChains.take(timerId)); | 203 setCurrentAsyncCallChain(0); |
yurys
2013/12/23 09:11:57
Can we test this branch?
aandrey
2013/12/23 12:09:38
Added new test: LayoutTests/inspector/debugger/asy
yurys
2013/12/23 12:40:31
Thank you!
| |
204 } | |
190 } | 205 } |
191 | 206 |
192 void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames) | 207 void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames) |
193 { | 208 { |
194 DEFINE_STATIC_LOCAL(String, requestAnimationFrameName, ("requestAnimationFra me")); | 209 DEFINE_STATIC_LOCAL(String, requestAnimationFrameName, ("requestAnimationFra me")); |
195 | 210 |
196 ASSERT(context); | 211 ASSERT(context); |
197 ASSERT(isEnabled()); | 212 ASSERT(isEnabled()); |
198 if (!validateCallFrames(callFrames)) | 213 if (!validateCallFrames(callFrames)) |
199 return; | 214 return; |
(...skipping 13 matching lines...) Expand all Loading... | |
213 } | 228 } |
214 | 229 |
215 void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in t callbackId) | 230 void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in t callbackId) |
216 { | 231 { |
217 ASSERT(context); | 232 ASSERT(context); |
218 ASSERT(isEnabled()); | 233 ASSERT(isEnabled()); |
219 ASSERT(callbackId > 0); | 234 ASSERT(callbackId > 0); |
220 ASSERT(!m_currentAsyncCallChain); | 235 ASSERT(!m_currentAsyncCallChain); |
221 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 236 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
222 setCurrentAsyncCallChain(data->m_animationFrameCallChains.take(callbackI d)); | 237 setCurrentAsyncCallChain(data->m_animationFrameCallChains.take(callbackI d)); |
238 else | |
239 setCurrentAsyncCallChain(0); | |
223 } | 240 } |
224 | 241 |
225 void AsyncCallStackTracker::didAddEventListener(EventTarget* eventTarget, const AtomicString& eventType, EventListener* listener, bool useCapture, const ScriptV alue& callFrames) | 242 void AsyncCallStackTracker::didAddEventListener(EventTarget* eventTarget, const AtomicString& eventType, EventListener* listener, bool useCapture, const ScriptV alue& callFrames) |
226 { | 243 { |
227 ASSERT(eventTarget->executionContext()); | 244 ASSERT(eventTarget->executionContext()); |
228 ASSERT(isEnabled()); | 245 ASSERT(isEnabled()); |
229 if (!validateCallFrames(callFrames)) | 246 if (!validateCallFrames(callFrames) || xmlHttpRequestFor(eventTarget)) |
230 return; | 247 return; |
231 | 248 |
232 StringBuilder description; | 249 StringBuilder description; |
233 description.append(eventTarget->interfaceName()); | 250 description.append(eventTarget->interfaceName()); |
234 if (!description.isEmpty()) | 251 if (!description.isEmpty()) |
235 description.append("."); | 252 description.append("."); |
236 if (listener->isAttribute()) { | 253 if (listener->isAttribute()) { |
237 description.append("on"); | 254 description.append("on"); |
238 description.append(eventType); | 255 description.append(eventType); |
239 } else { | 256 } else { |
(...skipping 19 matching lines...) Expand all Loading... | |
259 ASSERT(eventTarget->executionContext()); | 276 ASSERT(eventTarget->executionContext()); |
260 ASSERT(isEnabled()); | 277 ASSERT(isEnabled()); |
261 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget-> executionContext())) | 278 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget-> executionContext())) |
262 data->m_eventTargetCallChains.remove(eventTarget); | 279 data->m_eventTargetCallChains.remove(eventTarget); |
263 } | 280 } |
264 | 281 |
265 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom icString& eventType, EventListener* listener, bool useCapture) | 282 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom icString& eventType, EventListener* listener, bool useCapture) |
266 { | 283 { |
267 ASSERT(eventTarget->executionContext()); | 284 ASSERT(eventTarget->executionContext()); |
268 ASSERT(isEnabled()); | 285 ASSERT(isEnabled()); |
286 if (XMLHttpRequest* xhr = xmlHttpRequestFor(eventTarget)) { | |
287 willHandleXHREvent(xhr, eventTarget, eventType); | |
288 return; | |
289 } | |
269 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget-> executionContext())) | 290 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget-> executionContext())) |
270 setCurrentAsyncCallChain(data->findEventListenerData(eventTarget, eventT ype, RegisteredEventListener(listener, useCapture))); | 291 setCurrentAsyncCallChain(data->findEventListenerData(eventTarget, eventT ype, RegisteredEventListener(listener, useCapture))); |
292 else | |
293 setCurrentAsyncCallChain(0); | |
294 } | |
295 | |
296 void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue& callFrames) | |
297 { | |
298 DEFINE_STATIC_LOCAL(String, xhrSendName, ("XMLHttpRequest.send")); | |
yurys
2013/12/23 09:11:57
This is not thread-safe and may be called on Worke
aandrey
2013/12/23 12:09:38
Done. I also removed other DEFINE_STATIC_LOCAL's
| |
299 | |
300 ASSERT(xhr->executionContext()); | |
301 ASSERT(isEnabled()); | |
302 if (!validateCallFrames(callFrames)) | |
303 return; | |
304 ExecutionContextData* data = createContextDataIfNeeded(xhr->executionContext ()); | |
305 data->m_xhrCallChains.set(xhr, createAsyncCallChain(xhrSendName, callFrames) ); | |
306 } | |
307 | |
308 void AsyncCallStackTracker::willHandleXHREvent(XMLHttpRequest* xhr, EventTarget* eventTarget, const AtomicString& eventType) | |
309 { | |
310 ASSERT(xhr->executionContext()); | |
311 ASSERT(isEnabled()); | |
312 if (ExecutionContextData* data = m_executionContextDataMap.get(xhr->executio nContext())) { | |
313 if (xhr == eventTarget && eventType == EventTypeNames::loadend) | |
yurys
2013/12/23 09:11:57
What is xhr == eventTarget? Is it check for upload
aandrey
2013/12/23 12:09:38
Yes, essentially.
The "loadend" on XHR is the corr
yurys
2013/12/23 12:40:31
Consider assigning it to a named variable like isU
aandrey
2013/12/23 13:01:29
Assigned to isXHRDownload.
| |
314 setCurrentAsyncCallChain(data->m_xhrCallChains.take(xhr)); | |
315 else | |
316 setCurrentAsyncCallChain(data->m_xhrCallChains.get(xhr)); | |
317 } else { | |
318 setCurrentAsyncCallChain(0); | |
319 } | |
271 } | 320 } |
272 | 321 |
273 void AsyncCallStackTracker::didFireAsyncCall() | 322 void AsyncCallStackTracker::didFireAsyncCall() |
274 { | 323 { |
275 setCurrentAsyncCallChain(0); | 324 clearCurrentAsyncCallChain(); |
276 } | 325 } |
277 | 326 |
278 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA syncCallChain(const String& description, const ScriptValue& callFrames) | 327 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA syncCallChain(const String& description, const ScriptValue& callFrames) |
279 { | 328 { |
280 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr acker::AsyncCallChain()); | 329 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr acker::AsyncCallChain()); |
281 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); | 330 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); |
282 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta ck(description, callFrames))); | 331 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta ck(description, callFrames))); |
283 return chain.release(); | 332 return chain.release(); |
284 } | 333 } |
285 | 334 |
286 void AsyncCallStackTracker::setCurrentAsyncCallChain(PassRefPtr<AsyncCallChain> chain) | 335 void AsyncCallStackTracker::setCurrentAsyncCallChain(PassRefPtr<AsyncCallChain> chain) |
287 { | 336 { |
288 if (m_currentAsyncCallChain) { | 337 if (m_currentAsyncCallChain) { |
289 m_nestedAsyncCallCount += chain ? 1 : -1; | 338 ++m_nestedAsyncCallCount; |
290 if (!m_nestedAsyncCallCount) | |
291 m_currentAsyncCallChain = 0; | |
292 } else if (chain) { | 339 } else if (chain) { |
293 m_currentAsyncCallChain = chain; | 340 m_currentAsyncCallChain = chain; |
294 m_nestedAsyncCallCount = 1; | 341 m_nestedAsyncCallCount = 1; |
295 } | 342 } |
296 } | 343 } |
297 | 344 |
345 void AsyncCallStackTracker::clearCurrentAsyncCallChain() | |
346 { | |
347 if (!m_nestedAsyncCallCount) | |
348 return; | |
349 --m_nestedAsyncCallCount; | |
350 if (!m_nestedAsyncCallCount) | |
351 m_currentAsyncCallChain.clear(); | |
352 } | |
353 | |
298 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth) | 354 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth) |
299 { | 355 { |
300 while (chain->m_callStacks.size() > maxDepth) | 356 while (chain->m_callStacks.size() > maxDepth) |
301 chain->m_callStacks.removeLast(); | 357 chain->m_callStacks.removeLast(); |
302 } | 358 } |
303 | 359 |
304 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) | 360 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) |
305 { | 361 { |
306 return !callFrames.hasNoValue(); | 362 return !callFrames.hasNoValue(); |
307 } | 363 } |
308 | 364 |
309 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex tDataIfNeeded(ExecutionContext* context) | 365 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex tDataIfNeeded(ExecutionContext* context) |
310 { | 366 { |
311 ExecutionContextData* data = m_executionContextDataMap.get(context); | 367 ExecutionContextData* data = m_executionContextDataMap.get(context); |
312 if (!data) { | 368 if (!data) { |
313 data = new AsyncCallStackTracker::ExecutionContextData(this, context); | 369 data = new AsyncCallStackTracker::ExecutionContextData(this, context); |
314 m_executionContextDataMap.set(context, data); | 370 m_executionContextDataMap.set(context, data); |
315 } | 371 } |
316 return data; | 372 return data; |
317 } | 373 } |
318 | 374 |
319 void AsyncCallStackTracker::clear() | 375 void AsyncCallStackTracker::clear() |
320 { | 376 { |
321 m_currentAsyncCallChain = 0; | 377 m_currentAsyncCallChain.clear(); |
322 m_nestedAsyncCallCount = 0; | 378 m_nestedAsyncCallCount = 0; |
323 ExecutionContextDataMap copy; | 379 ExecutionContextDataMap copy; |
324 m_executionContextDataMap.swap(copy); | 380 m_executionContextDataMap.swap(copy); |
325 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e nd(); ++it) | 381 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e nd(); ++it) |
326 delete it->value; | 382 delete it->value; |
327 } | 383 } |
328 | 384 |
329 } // namespace WebCore | 385 } // namespace WebCore |
OLD | NEW |