Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: Source/core/inspector/AsyncCallStackTracker.cpp

Issue 118293002: DevTools: Support XHR async call stacks in the debugger. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: split tests Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698