Chromium Code Reviews| 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); |