| Index: Source/core/inspector/AsyncCallStackTracker.cpp
|
| diff --git a/Source/core/inspector/AsyncCallStackTracker.cpp b/Source/core/inspector/AsyncCallStackTracker.cpp
|
| index 841c94667395ff8770fe72ba997c60f5fc033a48..7d9c579e3a41f1e919aee1a9a1eac10647f542d5 100644
|
| --- a/Source/core/inspector/AsyncCallStackTracker.cpp
|
| +++ b/Source/core/inspector/AsyncCallStackTracker.cpp
|
| @@ -35,8 +35,20 @@
|
| #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 {
|
| +
|
| +static const char setTimeoutName[] = "setTimeout";
|
| +static const char setIntervalName[] = "setInterval";
|
| +static const char requestAnimationFrameName[] = "requestAnimationFrame";
|
| +static const char xhrSendName[] = "XMLHttpRequest.send";
|
| +
|
| +}
|
| +
|
| namespace WebCore {
|
|
|
| class AsyncCallStackTracker::ExecutionContextData : public ContextLifecycleObserver {
|
| @@ -111,8 +123,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* toXmlHttpRequest(EventTarget* eventTarget)
|
| +{
|
| + 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)
|
| @@ -147,9 +170,6 @@ const AsyncCallStackTracker::AsyncCallChain* AsyncCallStackTracker::currentAsync
|
|
|
| void AsyncCallStackTracker::didInstallTimer(ExecutionContext* context, int timerId, bool singleShot, const ScriptValue& callFrames)
|
| {
|
| - DEFINE_STATIC_LOCAL(String, setTimeoutName, ("setTimeout"));
|
| - DEFINE_STATIC_LOCAL(String, setIntervalName, ("setInterval"));
|
| -
|
| ASSERT(context);
|
| ASSERT(isEnabled());
|
| if (!validateCallFrames(callFrames))
|
| @@ -180,19 +200,18 @@ 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);
|
| + }
|
| }
|
|
|
| void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames)
|
| {
|
| - DEFINE_STATIC_LOCAL(String, requestAnimationFrameName, ("requestAnimationFrame"));
|
| -
|
| ASSERT(context);
|
| ASSERT(isEnabled());
|
| if (!validateCallFrames(callFrames))
|
| @@ -220,13 +239,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) || toXmlHttpRequest(eventTarget))
|
| return;
|
|
|
| StringBuilder description;
|
| @@ -266,13 +287,44 @@ void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom
|
| {
|
| ASSERT(eventTarget->executionContext());
|
| ASSERT(isEnabled());
|
| + if (XMLHttpRequest* xhr = toXmlHttpRequest(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)
|
| +{
|
| + 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())) {
|
| + bool isXHRDownload = (xhr == eventTarget);
|
| + if (isXHRDownload && eventType == EventTypeNames::loadend)
|
| + 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 +338,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 +377,7 @@ AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex
|
|
|
| void AsyncCallStackTracker::clear()
|
| {
|
| - m_currentAsyncCallChain = 0;
|
| + m_currentAsyncCallChain.clear();
|
| m_nestedAsyncCallCount = 0;
|
| ExecutionContextDataMap copy;
|
| m_executionContextDataMap.swap(copy);
|
|
|