OLD | NEW |
---|---|
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 13 matching lines...) Expand all Loading... | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
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" | |
35 #include "core/dom/ExecutionContext.h" | |
36 | |
34 namespace WebCore { | 37 namespace WebCore { |
35 | 38 |
36 #ifdef DEBUG_ASYNC_CALLS_DEBUGGER_SUPPORT | 39 #ifdef DEBUG_ASYNC_CALLS_DEBUGGER_SUPPORT |
37 namespace { | 40 namespace { |
38 unsigned totalAsyncCallStacks = 0; | 41 unsigned totalAsyncCallStacks = 0; |
42 unsigned totalExecutionContextData = 0; | |
39 } | 43 } |
40 #endif | 44 #endif |
41 | 45 |
46 class AsyncCallStackTracker::ExecutionContextData : public ContextLifecycleObser ver { | |
47 WTF_MAKE_FAST_ALLOCATED; | |
48 public: | |
49 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu tionContext) | |
50 : ContextLifecycleObserver(executionContext) | |
51 , m_tracker(tracker) | |
52 { | |
53 #ifdef DEBUG_ASYNC_CALLS_DEBUGGER_SUPPORT | |
pfeldman
2013/12/10 15:45:02
remove
| |
54 fprintf(stderr, "ExecutionContextData::ExecutionContextData() %u\n", ++t otalExecutionContextData); | |
55 #endif | |
56 } | |
57 | |
58 #ifdef DEBUG_ASYNC_CALLS_DEBUGGER_SUPPORT | |
59 virtual ~ExecutionContextData() | |
60 { | |
61 fprintf(stderr, "ExecutionContextData::~ExecutionContextData() %u\n", -- totalExecutionContextData); | |
62 } | |
63 #endif | |
64 | |
65 virtual void contextDestroyed() OVERRIDE | |
66 { | |
67 ContextLifecycleObserver::contextDestroyed(); | |
68 m_tracker->contextDestroyed(executionContext()); | |
69 } | |
70 | |
71 private: | |
72 friend class AsyncCallStackTracker; | |
73 AsyncCallStackTracker* m_tracker; | |
74 HashSet<int> m_intervalTimerIds; | |
75 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; | |
76 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; | |
77 }; | |
78 | |
42 AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const ScriptValue& callFra mes) | 79 AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const ScriptValue& callFra mes) |
43 : m_callFrames(callFrames) | 80 : m_callFrames(callFrames) |
44 { | 81 { |
45 #ifdef DEBUG_ASYNC_CALLS_DEBUGGER_SUPPORT | 82 #ifdef DEBUG_ASYNC_CALLS_DEBUGGER_SUPPORT |
46 fprintf(stderr, "AsyncCallStack::AsyncCallStack() %u\n", ++totalAsyncCallSta cks); | 83 fprintf(stderr, "AsyncCallStack::AsyncCallStack() %u\n", ++totalAsyncCallSta cks); |
47 #endif | 84 #endif |
48 } | 85 } |
49 | 86 |
50 AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack() | 87 AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack() |
51 { | 88 { |
(...skipping 20 matching lines...) Expand all Loading... | |
72 } | 109 } |
73 } | 110 } |
74 | 111 |
75 const AsyncCallStackTracker::AsyncCallChain* AsyncCallStackTracker::currentAsync CallChain() const | 112 const AsyncCallStackTracker::AsyncCallChain* AsyncCallStackTracker::currentAsync CallChain() const |
76 { | 113 { |
77 if (m_currentAsyncCallChain) | 114 if (m_currentAsyncCallChain) |
78 ensureMaxAsyncCallChainDepth(m_currentAsyncCallChain.get(), m_maxAsyncCa llStackDepth); | 115 ensureMaxAsyncCallChainDepth(m_currentAsyncCallChain.get(), m_maxAsyncCa llStackDepth); |
79 return m_currentAsyncCallChain.get(); | 116 return m_currentAsyncCallChain.get(); |
80 } | 117 } |
81 | 118 |
82 void AsyncCallStackTracker::didInstallTimer(int timerId, bool singleShot, const ScriptValue& callFrames) | 119 void AsyncCallStackTracker::didInstallTimer(ExecutionContext* context, int timer Id, bool singleShot, const ScriptValue& callFrames) |
83 { | 120 { |
84 ASSERT(isEnabled()); | 121 ASSERT(isEnabled()); |
85 if (!validateCallFrames(callFrames)) | 122 if (!validateCallFrames(callFrames)) |
86 return; | 123 return; |
87 ASSERT(timerId > 0); | 124 ASSERT(timerId > 0); |
88 m_timerCallChains.set(timerId, createAsyncCallChain(callFrames)); | 125 ExecutionContextData* data = createContextDataIfNeeded(context); |
126 data->m_timerCallChains.set(timerId, createAsyncCallChain(callFrames)); | |
89 if (!singleShot) | 127 if (!singleShot) |
90 m_intervalTimerIds.add(timerId); | 128 data->m_intervalTimerIds.add(timerId); |
91 } | 129 } |
92 | 130 |
93 void AsyncCallStackTracker::didRemoveTimer(int timerId) | 131 void AsyncCallStackTracker::didRemoveTimer(ExecutionContext* context, int timerI d) |
94 { | 132 { |
95 if (!isEnabled() || timerId <= 0) | 133 if (!isEnabled() || timerId <= 0) |
96 return; | 134 return; |
97 m_intervalTimerIds.remove(timerId); | 135 ExecutionContextData* data = m_executionContextDataMap.get(context); |
98 m_timerCallChains.remove(timerId); | 136 if (!data) |
137 return; | |
138 data->m_intervalTimerIds.remove(timerId); | |
139 data->m_timerCallChains.remove(timerId); | |
99 } | 140 } |
100 | 141 |
101 void AsyncCallStackTracker::willFireTimer(int timerId) | 142 void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId ) |
102 { | 143 { |
103 if (!isEnabled()) | 144 if (!isEnabled()) |
104 return; | 145 return; |
105 ASSERT(timerId > 0); | 146 ASSERT(timerId > 0); |
106 ASSERT(!m_currentAsyncCallChain); | 147 ASSERT(!m_currentAsyncCallChain); |
107 if (m_intervalTimerIds.contains(timerId)) | 148 ExecutionContextData* data = m_executionContextDataMap.get(context); |
108 m_currentAsyncCallChain = m_timerCallChains.get(timerId); | 149 if (!data) |
150 return; | |
151 if (data->m_intervalTimerIds.contains(timerId)) | |
152 m_currentAsyncCallChain = data->m_timerCallChains.get(timerId); | |
109 else | 153 else |
110 m_currentAsyncCallChain = m_timerCallChains.take(timerId); | 154 m_currentAsyncCallChain = data->m_timerCallChains.take(timerId); |
111 } | 155 } |
112 | 156 |
113 void AsyncCallStackTracker::didRequestAnimationFrame(int callbackId, const Scrip tValue& callFrames) | 157 void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames) |
114 { | 158 { |
115 ASSERT(isEnabled()); | 159 ASSERT(isEnabled()); |
116 if (!validateCallFrames(callFrames)) | 160 if (!validateCallFrames(callFrames)) |
117 return; | 161 return; |
118 ASSERT(callbackId > 0); | 162 ASSERT(callbackId > 0); |
119 m_animationFrameCallChains.set(callbackId, createAsyncCallChain(callFrames)) ; | 163 ExecutionContextData* data = createContextDataIfNeeded(context); |
164 data->m_animationFrameCallChains.set(callbackId, createAsyncCallChain(callFr ames)); | |
120 } | 165 } |
121 | 166 |
122 void AsyncCallStackTracker::didCancelAnimationFrame(int callbackId) | 167 void AsyncCallStackTracker::didCancelAnimationFrame(ExecutionContext* context, i nt callbackId) |
123 { | 168 { |
124 if (!isEnabled() || callbackId <= 0) | 169 if (!isEnabled() || callbackId <= 0) |
125 return; | 170 return; |
126 m_animationFrameCallChains.remove(callbackId); | 171 ExecutionContextData* data = m_executionContextDataMap.get(context); |
172 if (!data) | |
173 return; | |
174 data->m_animationFrameCallChains.remove(callbackId); | |
127 } | 175 } |
128 | 176 |
129 void AsyncCallStackTracker::willFireAnimationFrame(int callbackId) | 177 void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in t callbackId) |
130 { | 178 { |
131 if (!isEnabled()) | 179 if (!isEnabled()) |
132 return; | 180 return; |
133 ASSERT(callbackId > 0); | 181 ASSERT(callbackId > 0); |
134 ASSERT(!m_currentAsyncCallChain); | 182 ASSERT(!m_currentAsyncCallChain); |
135 m_currentAsyncCallChain = m_animationFrameCallChains.take(callbackId); | 183 ExecutionContextData* data = m_executionContextDataMap.get(context); |
184 if (!data) | |
185 return; | |
186 m_currentAsyncCallChain = data->m_animationFrameCallChains.take(callbackId); | |
136 } | 187 } |
137 | 188 |
138 void AsyncCallStackTracker::didFireAsyncCall() | 189 void AsyncCallStackTracker::didFireAsyncCall() |
139 { | 190 { |
140 m_currentAsyncCallChain = 0; | 191 m_currentAsyncCallChain = 0; |
141 } | 192 } |
142 | 193 |
143 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA syncCallChain(const ScriptValue& callFrames) | 194 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA syncCallChain(const ScriptValue& callFrames) |
144 { | 195 { |
145 ASSERT(isEnabled()); | 196 ASSERT(isEnabled()); |
146 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr acker::AsyncCallChain()); | 197 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr acker::AsyncCallChain()); |
147 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); | 198 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); |
148 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta ck(callFrames))); | 199 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta ck(callFrames))); |
149 return chain.release(); | 200 return chain.release(); |
150 } | 201 } |
151 | 202 |
152 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth) | 203 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth) |
153 { | 204 { |
154 while (chain->m_callStacks.size() > maxDepth) | 205 while (chain->m_callStacks.size() > maxDepth) |
155 chain->m_callStacks.removeLast(); | 206 chain->m_callStacks.removeLast(); |
156 } | 207 } |
157 | 208 |
158 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) | 209 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) |
159 { | 210 { |
160 return !callFrames.hasNoValue() && callFrames.isObject(); | 211 return !callFrames.hasNoValue() && callFrames.isObject(); |
161 } | 212 } |
162 | 213 |
214 void AsyncCallStackTracker::contextDestroyed(ExecutionContext* context) | |
215 { | |
216 ExecutionContextData* data = m_executionContextDataMap.take(context); | |
217 if (data) | |
218 delete data; | |
219 } | |
220 | |
221 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex tDataIfNeeded(ExecutionContext* context) | |
222 { | |
223 ExecutionContextData* data = m_executionContextDataMap.get(context); | |
224 if (!data) { | |
225 data = new AsyncCallStackTracker::ExecutionContextData(this, context); | |
226 m_executionContextDataMap.set(context, data); | |
227 } | |
228 return data; | |
229 } | |
230 | |
163 void AsyncCallStackTracker::clear() | 231 void AsyncCallStackTracker::clear() |
164 { | 232 { |
165 m_currentAsyncCallChain = 0; | 233 m_currentAsyncCallChain = 0; |
166 m_intervalTimerIds.clear(); | 234 Vector<ExecutionContextData*> contextsData; |
167 m_timerCallChains.clear(); | 235 copyValuesToVector(m_executionContextDataMap, contextsData); |
168 m_animationFrameCallChains.clear(); | 236 m_executionContextDataMap.clear(); |
237 for (Vector<ExecutionContextData*>::const_iterator it = contextsData.begin() ; it != contextsData.end(); ++it) | |
238 delete *it; | |
169 } | 239 } |
170 | 240 |
171 } // namespace WebCore | 241 } // namespace WebCore |
OLD | NEW |