Chromium Code Reviews| Index: Source/core/inspector/AsyncCallStackTracker.cpp |
| diff --git a/Source/core/inspector/AsyncCallStackTracker.cpp b/Source/core/inspector/AsyncCallStackTracker.cpp |
| index 0e68ba6bcc381de881bbe2941e7c451e652d7d72..1ae426fe2521812f8db03b9cb7f29c84ef34a2aa 100644 |
| --- a/Source/core/inspector/AsyncCallStackTracker.cpp |
| +++ b/Source/core/inspector/AsyncCallStackTracker.cpp |
| @@ -31,14 +31,51 @@ |
| #include "config.h" |
| #include "core/inspector/AsyncCallStackTracker.h" |
| +#include "core/dom/ContextLifecycleObserver.h" |
| +#include "core/dom/ExecutionContext.h" |
| + |
| namespace WebCore { |
| #ifdef DEBUG_ASYNC_CALLS_DEBUGGER_SUPPORT |
| namespace { |
| unsigned totalAsyncCallStacks = 0; |
| +unsigned totalExecutionContextData = 0; |
| } |
| #endif |
| +class AsyncCallStackTracker::ExecutionContextData : public ContextLifecycleObserver { |
| + WTF_MAKE_FAST_ALLOCATED; |
| +public: |
| + ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* executionContext) |
| + : ContextLifecycleObserver(executionContext) |
| + , m_tracker(tracker) |
| + { |
| +#ifdef DEBUG_ASYNC_CALLS_DEBUGGER_SUPPORT |
|
pfeldman
2013/12/10 15:45:02
remove
|
| + fprintf(stderr, "ExecutionContextData::ExecutionContextData() %u\n", ++totalExecutionContextData); |
| +#endif |
| + } |
| + |
| +#ifdef DEBUG_ASYNC_CALLS_DEBUGGER_SUPPORT |
| + virtual ~ExecutionContextData() |
| + { |
| + fprintf(stderr, "ExecutionContextData::~ExecutionContextData() %u\n", --totalExecutionContextData); |
| + } |
| +#endif |
| + |
| + virtual void contextDestroyed() OVERRIDE |
| + { |
| + ContextLifecycleObserver::contextDestroyed(); |
| + m_tracker->contextDestroyed(executionContext()); |
| + } |
| + |
| +private: |
| + friend class AsyncCallStackTracker; |
| + AsyncCallStackTracker* m_tracker; |
| + HashSet<int> m_intervalTimerIds; |
| + HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; |
| + HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; |
| +}; |
| + |
| AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const ScriptValue& callFrames) |
| : m_callFrames(callFrames) |
| { |
| @@ -79,60 +116,74 @@ const AsyncCallStackTracker::AsyncCallChain* AsyncCallStackTracker::currentAsync |
| return m_currentAsyncCallChain.get(); |
| } |
| -void AsyncCallStackTracker::didInstallTimer(int timerId, bool singleShot, const ScriptValue& callFrames) |
| +void AsyncCallStackTracker::didInstallTimer(ExecutionContext* context, int timerId, bool singleShot, const ScriptValue& callFrames) |
| { |
| ASSERT(isEnabled()); |
| if (!validateCallFrames(callFrames)) |
| return; |
| ASSERT(timerId > 0); |
| - m_timerCallChains.set(timerId, createAsyncCallChain(callFrames)); |
| + ExecutionContextData* data = createContextDataIfNeeded(context); |
| + data->m_timerCallChains.set(timerId, createAsyncCallChain(callFrames)); |
| if (!singleShot) |
| - m_intervalTimerIds.add(timerId); |
| + data->m_intervalTimerIds.add(timerId); |
| } |
| -void AsyncCallStackTracker::didRemoveTimer(int timerId) |
| +void AsyncCallStackTracker::didRemoveTimer(ExecutionContext* context, int timerId) |
| { |
| if (!isEnabled() || timerId <= 0) |
| return; |
| - m_intervalTimerIds.remove(timerId); |
| - m_timerCallChains.remove(timerId); |
| + ExecutionContextData* data = m_executionContextDataMap.get(context); |
| + if (!data) |
| + return; |
| + data->m_intervalTimerIds.remove(timerId); |
| + data->m_timerCallChains.remove(timerId); |
| } |
| -void AsyncCallStackTracker::willFireTimer(int timerId) |
| +void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId) |
| { |
| if (!isEnabled()) |
| return; |
| ASSERT(timerId > 0); |
| ASSERT(!m_currentAsyncCallChain); |
| - if (m_intervalTimerIds.contains(timerId)) |
| - m_currentAsyncCallChain = m_timerCallChains.get(timerId); |
| + ExecutionContextData* data = m_executionContextDataMap.get(context); |
| + if (!data) |
| + return; |
| + if (data->m_intervalTimerIds.contains(timerId)) |
| + m_currentAsyncCallChain = data->m_timerCallChains.get(timerId); |
| else |
| - m_currentAsyncCallChain = m_timerCallChains.take(timerId); |
| + m_currentAsyncCallChain = data->m_timerCallChains.take(timerId); |
| } |
| -void AsyncCallStackTracker::didRequestAnimationFrame(int callbackId, const ScriptValue& callFrames) |
| +void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames) |
| { |
| ASSERT(isEnabled()); |
| if (!validateCallFrames(callFrames)) |
| return; |
| ASSERT(callbackId > 0); |
| - m_animationFrameCallChains.set(callbackId, createAsyncCallChain(callFrames)); |
| + ExecutionContextData* data = createContextDataIfNeeded(context); |
| + data->m_animationFrameCallChains.set(callbackId, createAsyncCallChain(callFrames)); |
| } |
| -void AsyncCallStackTracker::didCancelAnimationFrame(int callbackId) |
| +void AsyncCallStackTracker::didCancelAnimationFrame(ExecutionContext* context, int callbackId) |
| { |
| if (!isEnabled() || callbackId <= 0) |
| return; |
| - m_animationFrameCallChains.remove(callbackId); |
| + ExecutionContextData* data = m_executionContextDataMap.get(context); |
| + if (!data) |
| + return; |
| + data->m_animationFrameCallChains.remove(callbackId); |
| } |
| -void AsyncCallStackTracker::willFireAnimationFrame(int callbackId) |
| +void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, int callbackId) |
| { |
| if (!isEnabled()) |
| return; |
| ASSERT(callbackId > 0); |
| ASSERT(!m_currentAsyncCallChain); |
| - m_currentAsyncCallChain = m_animationFrameCallChains.take(callbackId); |
| + ExecutionContextData* data = m_executionContextDataMap.get(context); |
| + if (!data) |
| + return; |
| + m_currentAsyncCallChain = data->m_animationFrameCallChains.take(callbackId); |
| } |
| void AsyncCallStackTracker::didFireAsyncCall() |
| @@ -160,12 +211,31 @@ bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) |
| return !callFrames.hasNoValue() && callFrames.isObject(); |
| } |
| +void AsyncCallStackTracker::contextDestroyed(ExecutionContext* context) |
| +{ |
| + ExecutionContextData* data = m_executionContextDataMap.take(context); |
| + if (data) |
| + delete data; |
| +} |
| + |
| +AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContextDataIfNeeded(ExecutionContext* context) |
| +{ |
| + ExecutionContextData* data = m_executionContextDataMap.get(context); |
| + if (!data) { |
| + data = new AsyncCallStackTracker::ExecutionContextData(this, context); |
| + m_executionContextDataMap.set(context, data); |
| + } |
| + return data; |
| +} |
| + |
| void AsyncCallStackTracker::clear() |
| { |
| m_currentAsyncCallChain = 0; |
| - m_intervalTimerIds.clear(); |
| - m_timerCallChains.clear(); |
| - m_animationFrameCallChains.clear(); |
| + Vector<ExecutionContextData*> contextsData; |
| + copyValuesToVector(m_executionContextDataMap, contextsData); |
| + m_executionContextDataMap.clear(); |
| + for (Vector<ExecutionContextData*>::const_iterator it = contextsData.begin(); it != contextsData.end(); ++it) |
| + delete *it; |
| } |
| } // namespace WebCore |