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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: Source/core/inspector/AsyncCallStackTracker.cpp
diff --git a/Source/core/inspector/AsyncCallStackTracker.cpp b/Source/core/inspector/AsyncCallStackTracker.cpp
index 841c94667395ff8770fe72ba997c60f5fc033a48..a6c2424d863d569d1661d3a4910e486a768a9e26 100644
--- a/Source/core/inspector/AsyncCallStackTracker.cpp
+++ b/Source/core/inspector/AsyncCallStackTracker.cpp
@@ -35,6 +35,9 @@
#include "core/dom/ExecutionContext.h"
#include "core/events/EventTarget.h"
#include "core/events/RegisteredEventListener.h"
+#include "core/xml/XMLHttpRequest.h"
+#include "core/xml/XMLHttpRequestUpload.h"
+#include "wtf/text/AtomicStringHash.h"
#include "wtf/text/StringBuilder.h"
namespace WebCore {
@@ -111,8 +114,19 @@ public:
HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains;
HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains;
HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap> m_eventTargetCallChains;
+ HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains;
};
+static XMLHttpRequest* xmlHttpRequestFor(EventTarget* eventTarget)
yurys 2013/12/23 09:11:57 toXmlHttpRequest ?
aandrey 2013/12/23 12:09:38 Done.
+{
+ const AtomicString& interfaceName = eventTarget->interfaceName();
+ if (interfaceName == EventTargetNames::XMLHttpRequest)
+ return static_cast<XMLHttpRequest*>(eventTarget);
+ if (interfaceName == EventTargetNames::XMLHttpRequestUpload)
+ return static_cast<XMLHttpRequestUpload*>(eventTarget)->xmlHttpRequest();
+ return 0;
+}
+
AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const String& description, const ScriptValue& callFrames)
: m_description(description)
, m_callFrames(callFrames)
@@ -180,13 +194,14 @@ void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId
ASSERT(isEnabled());
ASSERT(timerId > 0);
ASSERT(!m_currentAsyncCallChain);
- ExecutionContextData* data = m_executionContextDataMap.get(context);
- if (!data)
- return;
- if (data->m_intervalTimerIds.contains(timerId))
- setCurrentAsyncCallChain(data->m_timerCallChains.get(timerId));
- else
- setCurrentAsyncCallChain(data->m_timerCallChains.take(timerId));
+ if (ExecutionContextData* data = m_executionContextDataMap.get(context)) {
+ if (data->m_intervalTimerIds.contains(timerId))
+ setCurrentAsyncCallChain(data->m_timerCallChains.get(timerId));
+ else
+ setCurrentAsyncCallChain(data->m_timerCallChains.take(timerId));
+ } else {
+ 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!
+ }
}
void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames)
@@ -220,13 +235,15 @@ void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in
ASSERT(!m_currentAsyncCallChain);
if (ExecutionContextData* data = m_executionContextDataMap.get(context))
setCurrentAsyncCallChain(data->m_animationFrameCallChains.take(callbackId));
+ else
+ setCurrentAsyncCallChain(0);
}
void AsyncCallStackTracker::didAddEventListener(EventTarget* eventTarget, const AtomicString& eventType, EventListener* listener, bool useCapture, const ScriptValue& callFrames)
{
ASSERT(eventTarget->executionContext());
ASSERT(isEnabled());
- if (!validateCallFrames(callFrames))
+ if (!validateCallFrames(callFrames) || xmlHttpRequestFor(eventTarget))
return;
StringBuilder description;
@@ -266,13 +283,45 @@ void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom
{
ASSERT(eventTarget->executionContext());
ASSERT(isEnabled());
+ if (XMLHttpRequest* xhr = xmlHttpRequestFor(eventTarget)) {
+ willHandleXHREvent(xhr, eventTarget, eventType);
+ return;
+ }
if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->executionContext()))
setCurrentAsyncCallChain(data->findEventListenerData(eventTarget, eventType, RegisteredEventListener(listener, useCapture)));
+ else
+ setCurrentAsyncCallChain(0);
+}
+
+void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue& callFrames)
+{
+ 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
+
+ ASSERT(xhr->executionContext());
+ ASSERT(isEnabled());
+ if (!validateCallFrames(callFrames))
+ return;
+ ExecutionContextData* data = createContextDataIfNeeded(xhr->executionContext());
+ data->m_xhrCallChains.set(xhr, createAsyncCallChain(xhrSendName, callFrames));
+}
+
+void AsyncCallStackTracker::willHandleXHREvent(XMLHttpRequest* xhr, EventTarget* eventTarget, const AtomicString& eventType)
+{
+ ASSERT(xhr->executionContext());
+ ASSERT(isEnabled());
+ if (ExecutionContextData* data = m_executionContextDataMap.get(xhr->executionContext())) {
+ 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.
+ setCurrentAsyncCallChain(data->m_xhrCallChains.take(xhr));
+ else
+ setCurrentAsyncCallChain(data->m_xhrCallChains.get(xhr));
+ } else {
+ setCurrentAsyncCallChain(0);
+ }
}
void AsyncCallStackTracker::didFireAsyncCall()
{
- setCurrentAsyncCallChain(0);
+ clearCurrentAsyncCallChain();
}
PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createAsyncCallChain(const String& description, const ScriptValue& callFrames)
@@ -286,15 +335,22 @@ PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA
void AsyncCallStackTracker::setCurrentAsyncCallChain(PassRefPtr<AsyncCallChain> chain)
{
if (m_currentAsyncCallChain) {
- m_nestedAsyncCallCount += chain ? 1 : -1;
- if (!m_nestedAsyncCallCount)
- m_currentAsyncCallChain = 0;
+ ++m_nestedAsyncCallCount;
} else if (chain) {
m_currentAsyncCallChain = chain;
m_nestedAsyncCallCount = 1;
}
}
+void AsyncCallStackTracker::clearCurrentAsyncCallChain()
+{
+ if (!m_nestedAsyncCallCount)
+ return;
+ --m_nestedAsyncCallCount;
+ if (!m_nestedAsyncCallCount)
+ m_currentAsyncCallChain.clear();
+}
+
void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth)
{
while (chain->m_callStacks.size() > maxDepth)
@@ -318,7 +374,7 @@ AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex
void AsyncCallStackTracker::clear()
{
- m_currentAsyncCallChain = 0;
+ m_currentAsyncCallChain.clear();
m_nestedAsyncCallCount = 0;
ExecutionContextDataMap copy;
m_executionContextDataMap.swap(copy);

Powered by Google App Engine
This is Rietveld 408576698