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 15 matching lines...) Expand all Loading... | |
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" | 34 #include "core/dom/ContextLifecycleObserver.h" |
35 #include "core/dom/ExecutionContext.h" | 35 #include "core/dom/ExecutionContext.h" |
36 #include "core/events/EventTarget.h" | |
37 #include "core/events/RegisteredEventListener.h" | |
38 #include "wtf/text/StringBuilder.h" | |
36 | 39 |
37 namespace WebCore { | 40 namespace WebCore { |
38 | 41 |
39 class AsyncCallStackTracker::ExecutionContextData : public ContextLifecycleObser ver { | 42 class AsyncCallStackTracker::ExecutionContextData : public ContextLifecycleObser ver { |
40 WTF_MAKE_FAST_ALLOCATED; | 43 WTF_MAKE_FAST_ALLOCATED; |
41 public: | 44 public: |
45 typedef std::pair<RegisteredEventListener, RefPtr<AsyncCallChain> > EventLis tenerAsyncCallChain; | |
46 typedef Vector<EventListenerAsyncCallChain, 1> EventListenerAsyncCallChainVe ctor; | |
47 typedef HashMap<AtomicString, EventListenerAsyncCallChainVector> EventListen erAsyncCallChainVectorHashMap; | |
48 | |
42 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu tionContext) | 49 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu tionContext) |
43 : ContextLifecycleObserver(executionContext) | 50 : ContextLifecycleObserver(executionContext) |
44 , m_tracker(tracker) | 51 , m_tracker(tracker) |
45 { | 52 { |
46 } | 53 } |
47 | 54 |
48 virtual void contextDestroyed() OVERRIDE | 55 virtual void contextDestroyed() OVERRIDE |
49 { | 56 { |
50 m_tracker->contextDestroyed(executionContext()); | 57 m_tracker->contextDestroyed(executionContext()); |
51 ContextLifecycleObserver::contextDestroyed(); | 58 ContextLifecycleObserver::contextDestroyed(); |
52 } | 59 } |
53 | 60 |
61 void add(EventTarget* eventTarget, const AtomicString& eventType, const Even tListenerAsyncCallChain& item) | |
yurys
2013/12/17 13:01:59
addEventListenerData?
aandrey
2013/12/17 13:24:03
Done.
| |
62 { | |
63 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap>::iterato r it = m_eventTargetCallChains.find(eventTarget); | |
64 if (it == m_eventTargetCallChains.end()) | |
65 it = m_eventTargetCallChains.set(eventTarget, EventListenerAsyncCall ChainVectorHashMap()).iterator; | |
66 EventListenerAsyncCallChainVectorHashMap& map = it->value; | |
67 EventListenerAsyncCallChainVectorHashMap::iterator it2 = map.find(eventT ype); | |
68 if (it2 == map.end()) | |
69 it2 = map.set(eventType, EventListenerAsyncCallChainVector()).iterat or; | |
70 it2->value.append(item); | |
71 } | |
72 | |
73 void remove(EventTarget* eventTarget, const AtomicString& eventType, const R egisteredEventListener& item) | |
74 { | |
75 get(eventTarget, eventType, item, true); | |
76 } | |
77 | |
78 PassRefPtr<AsyncCallChain> get(EventTarget* eventTarget, const AtomicString& eventType, const RegisteredEventListener& item, bool remove = false) | |
79 { | |
80 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap>::iterato r it = m_eventTargetCallChains.find(eventTarget); | |
81 if (it == m_eventTargetCallChains.end()) | |
82 return 0; | |
83 EventListenerAsyncCallChainVectorHashMap& map = it->value; | |
84 EventListenerAsyncCallChainVectorHashMap::iterator it2 = map.find(eventT ype); | |
85 if (it2 == map.end()) | |
86 return 0; | |
87 RefPtr<AsyncCallChain> result; | |
88 EventListenerAsyncCallChainVector& vector = it2->value; | |
89 for (size_t i = 0; i < vector.size(); ++i) { | |
90 if (vector[i].first == item) { | |
91 result = vector[i].second; | |
92 if (remove) { | |
93 vector.remove(i); | |
94 if (vector.isEmpty()) | |
95 map.remove(it2); | |
96 if (map.isEmpty()) | |
97 m_eventTargetCallChains.remove(it); | |
98 } | |
99 break; | |
100 } | |
101 } | |
102 return result.release(); | |
103 } | |
104 | |
54 private: | 105 private: |
55 friend class AsyncCallStackTracker; | 106 friend class AsyncCallStackTracker; |
yurys
2013/12/17 13:01:59
All these field should be public since ExecutionCo
aandrey
2013/12/17 13:24:03
Done.
| |
56 AsyncCallStackTracker* m_tracker; | 107 AsyncCallStackTracker* m_tracker; |
57 HashSet<int> m_intervalTimerIds; | 108 HashSet<int> m_intervalTimerIds; |
58 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; | 109 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; |
59 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; | 110 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; |
111 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap> m_eventTarge tCallChains; | |
60 }; | 112 }; |
61 | 113 |
62 AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const String& description, const ScriptValue& callFrames) | 114 AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const String& description, const ScriptValue& callFrames) |
63 : m_description(description) | 115 : m_description(description) |
64 , m_callFrames(callFrames) | 116 , m_callFrames(callFrames) |
65 { | 117 { |
66 } | 118 } |
67 | 119 |
68 AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack() | 120 AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack() |
69 { | 121 { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 data->m_intervalTimerIds.remove(timerId); | 170 data->m_intervalTimerIds.remove(timerId); |
119 data->m_timerCallChains.remove(timerId); | 171 data->m_timerCallChains.remove(timerId); |
120 } | 172 } |
121 | 173 |
122 void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId ) | 174 void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId ) |
123 { | 175 { |
124 ASSERT(context); | 176 ASSERT(context); |
125 if (!isEnabled()) | 177 if (!isEnabled()) |
126 return; | 178 return; |
127 ASSERT(timerId > 0); | 179 ASSERT(timerId > 0); |
128 ASSERT(!m_currentAsyncCallChain); | |
yurys
2013/12/17 13:01:59
Why did you remove this assert? Can it fail in a w
aandrey
2013/12/17 13:07:48
We can receive nested willHandleEvent() callbacks,
aandrey
2013/12/17 13:24:03
Done.
yurys
2013/12/18 09:22:15
I agree that it make sense for willHandleEvent whi
aandrey
2013/12/18 09:32:09
I think they can not. Added those ASSERT's back.
| |
129 ExecutionContextData* data = m_executionContextDataMap.get(context); | 180 ExecutionContextData* data = m_executionContextDataMap.get(context); |
130 if (!data) | 181 if (!data) |
131 return; | 182 return; |
132 if (data->m_intervalTimerIds.contains(timerId)) | 183 if (data->m_intervalTimerIds.contains(timerId)) |
133 m_currentAsyncCallChain = data->m_timerCallChains.get(timerId); | 184 setCurrentAsyncCallChain(data->m_timerCallChains.get(timerId)); |
134 else | 185 else |
135 m_currentAsyncCallChain = data->m_timerCallChains.take(timerId); | 186 setCurrentAsyncCallChain(data->m_timerCallChains.take(timerId)); |
136 } | 187 } |
137 | 188 |
138 void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames) | 189 void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames) |
139 { | 190 { |
140 DEFINE_STATIC_LOCAL(String, requestAnimationFrameName, ("requestAnimationFra me")); | 191 DEFINE_STATIC_LOCAL(String, requestAnimationFrameName, ("requestAnimationFra me")); |
141 | 192 |
142 ASSERT(context); | 193 ASSERT(context); |
143 ASSERT(isEnabled()); | 194 ASSERT(isEnabled()); |
144 if (!validateCallFrames(callFrames)) | 195 if (!validateCallFrames(callFrames)) |
145 return; | 196 return; |
(...skipping 10 matching lines...) Expand all Loading... | |
156 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 207 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
157 data->m_animationFrameCallChains.remove(callbackId); | 208 data->m_animationFrameCallChains.remove(callbackId); |
158 } | 209 } |
159 | 210 |
160 void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in t callbackId) | 211 void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in t callbackId) |
161 { | 212 { |
162 ASSERT(context); | 213 ASSERT(context); |
163 if (!isEnabled()) | 214 if (!isEnabled()) |
164 return; | 215 return; |
165 ASSERT(callbackId > 0); | 216 ASSERT(callbackId > 0); |
166 ASSERT(!m_currentAsyncCallChain); | |
167 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 217 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
168 m_currentAsyncCallChain = data->m_animationFrameCallChains.take(callback Id); | 218 setCurrentAsyncCallChain(data->m_animationFrameCallChains.take(callbackI d)); |
219 } | |
220 | |
221 void AsyncCallStackTracker::didAddEventListener(EventTarget* eventTarget, const AtomicString& eventType, EventListener* listener, bool useCapture, const ScriptV alue& callFrames) | |
222 { | |
223 ASSERT(eventTarget->executionContext()); | |
224 ASSERT(isEnabled()); | |
225 if (!validateCallFrames(callFrames)) | |
226 return; | |
227 | |
228 StringBuilder description; | |
229 description.append(eventTarget->interfaceName()); | |
230 if (!description.isEmpty()) | |
231 description.append("."); | |
232 if (listener->isAttribute()) { | |
233 description.append("on"); | |
234 description.append(eventType); | |
235 } else { | |
236 description.append("addEventListener(\""); | |
237 description.append(eventType); | |
238 description.append("\")"); | |
239 } | |
240 | |
241 ExecutionContextData* data = createContextDataIfNeeded(eventTarget->executio nContext()); | |
242 data->add(eventTarget, eventType, std::make_pair(RegisteredEventListener(lis tener, useCapture), createAsyncCallChain(description.toString(), callFrames))); | |
243 } | |
244 | |
245 void AsyncCallStackTracker::didRemoveEventListener(EventTarget* eventTarget, con st AtomicString& eventType, EventListener* listener, bool useCapture) | |
246 { | |
247 ASSERT(eventTarget->executionContext()); | |
248 if (!isEnabled()) | |
249 return; | |
250 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget-> executionContext())) | |
251 data->remove(eventTarget, eventType, RegisteredEventListener(listener, u seCapture)); | |
252 } | |
253 | |
254 void AsyncCallStackTracker::didRemoveAllEventListeners(EventTarget* eventTarget) | |
255 { | |
256 ASSERT(eventTarget->executionContext()); | |
257 if (!isEnabled()) | |
258 return; | |
259 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget-> executionContext())) | |
260 data->m_eventTargetCallChains.remove(eventTarget); | |
261 } | |
262 | |
263 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom icString& eventType, EventListener* listener, bool useCapture) | |
264 { | |
265 ASSERT(eventTarget->executionContext()); | |
266 if (!isEnabled()) | |
267 return; | |
268 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget-> executionContext())) | |
269 setCurrentAsyncCallChain(data->get(eventTarget, eventType, RegisteredEve ntListener(listener, useCapture))); | |
169 } | 270 } |
170 | 271 |
171 void AsyncCallStackTracker::didFireAsyncCall() | 272 void AsyncCallStackTracker::didFireAsyncCall() |
172 { | 273 { |
173 m_currentAsyncCallChain = 0; | 274 setCurrentAsyncCallChain(0); |
174 } | 275 } |
175 | 276 |
176 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA syncCallChain(const String& description, const ScriptValue& callFrames) | 277 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA syncCallChain(const String& description, const ScriptValue& callFrames) |
177 { | 278 { |
178 ASSERT(isEnabled()); | 279 ASSERT(isEnabled()); |
179 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr acker::AsyncCallChain()); | 280 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr acker::AsyncCallChain()); |
180 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); | 281 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); |
181 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta ck(description, callFrames))); | 282 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta ck(description, callFrames))); |
182 return chain.release(); | 283 return chain.release(); |
183 } | 284 } |
184 | 285 |
286 void AsyncCallStackTracker::setCurrentAsyncCallChain(PassRefPtr<AsyncCallChain> chain) | |
287 { | |
288 if (m_currentAsyncCallChain) { | |
289 m_nestedAsyncCallCount += chain ? 1 : -1; | |
290 if (!m_nestedAsyncCallCount) | |
291 m_currentAsyncCallChain = 0; | |
292 } else if (chain) { | |
293 m_currentAsyncCallChain = chain; | |
294 m_nestedAsyncCallCount = 1; | |
295 } | |
296 } | |
297 | |
185 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth) | 298 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth) |
186 { | 299 { |
187 while (chain->m_callStacks.size() > maxDepth) | 300 while (chain->m_callStacks.size() > maxDepth) |
188 chain->m_callStacks.removeLast(); | 301 chain->m_callStacks.removeLast(); |
189 } | 302 } |
190 | 303 |
191 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) | 304 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) |
192 { | 305 { |
193 return !callFrames.hasNoValue(); | 306 return !callFrames.hasNoValue(); |
194 } | 307 } |
(...skipping 11 matching lines...) Expand all Loading... | |
206 if (!data) { | 319 if (!data) { |
207 data = new AsyncCallStackTracker::ExecutionContextData(this, context); | 320 data = new AsyncCallStackTracker::ExecutionContextData(this, context); |
208 m_executionContextDataMap.set(context, data); | 321 m_executionContextDataMap.set(context, data); |
209 } | 322 } |
210 return data; | 323 return data; |
211 } | 324 } |
212 | 325 |
213 void AsyncCallStackTracker::clear() | 326 void AsyncCallStackTracker::clear() |
214 { | 327 { |
215 m_currentAsyncCallChain = 0; | 328 m_currentAsyncCallChain = 0; |
329 m_nestedAsyncCallCount = 0; | |
216 Vector<ExecutionContextData*> contextsData; | 330 Vector<ExecutionContextData*> contextsData; |
217 copyValuesToVector(m_executionContextDataMap, contextsData); | 331 copyValuesToVector(m_executionContextDataMap, contextsData); |
218 m_executionContextDataMap.clear(); | 332 m_executionContextDataMap.clear(); |
219 for (Vector<ExecutionContextData*>::const_iterator it = contextsData.begin() ; it != contextsData.end(); ++it) | 333 for (Vector<ExecutionContextData*>::const_iterator it = contextsData.begin() ; it != contextsData.end(); ++it) |
220 delete *it; | 334 delete *it; |
221 } | 335 } |
222 | 336 |
223 } // namespace WebCore | 337 } // namespace WebCore |
OLD | NEW |