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 17 matching lines...) Expand all Loading... |
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 "bindings/v8/V8RecursionScope.h" | 34 #include "bindings/v8/V8RecursionScope.h" |
35 #include "core/dom/ContextLifecycleObserver.h" | 35 #include "core/dom/ContextLifecycleObserver.h" |
36 #include "core/dom/ExecutionContext.h" | 36 #include "core/dom/ExecutionContext.h" |
37 #include "core/events/EventTarget.h" | 37 #include "core/events/EventTarget.h" |
38 #include "core/events/RegisteredEventListener.h" | |
39 #include "core/xml/XMLHttpRequest.h" | 38 #include "core/xml/XMLHttpRequest.h" |
40 #include "core/xml/XMLHttpRequestUpload.h" | 39 #include "core/xml/XMLHttpRequestUpload.h" |
41 #include "wtf/text/AtomicStringHash.h" | 40 #include "wtf/text/AtomicStringHash.h" |
42 #include "wtf/text/StringBuilder.h" | 41 #include "wtf/text/StringBuilder.h" |
43 | 42 |
44 namespace { | 43 namespace { |
45 | 44 |
46 static const char setTimeoutName[] = "setTimeout"; | 45 static const char setTimeoutName[] = "setTimeout"; |
47 static const char setIntervalName[] = "setInterval"; | 46 static const char setIntervalName[] = "setInterval"; |
48 static const char requestAnimationFrameName[] = "requestAnimationFrame"; | 47 static const char requestAnimationFrameName[] = "requestAnimationFrame"; |
49 static const char xhrSendName[] = "XMLHttpRequest.send"; | 48 static const char xhrSendName[] = "XMLHttpRequest.send"; |
50 static const char enqueueMutationRecordName[] = "Mutation"; | 49 static const char enqueueMutationRecordName[] = "Mutation"; |
51 | 50 |
52 } | 51 } |
53 | 52 |
54 namespace WebCore { | 53 namespace WebCore { |
55 | 54 |
56 class AsyncCallStackTracker::ExecutionContextData FINAL : public ContextLifecycl
eObserver { | 55 class AsyncCallStackTracker::ExecutionContextData FINAL : public ContextLifecycl
eObserver { |
57 WTF_MAKE_FAST_ALLOCATED; | 56 WTF_MAKE_FAST_ALLOCATED; |
58 public: | 57 public: |
59 typedef std::pair<RegisteredEventListener, RefPtr<AsyncCallChain> > EventLis
tenerAsyncCallChain; | |
60 typedef Vector<EventListenerAsyncCallChain, 1> EventListenerAsyncCallChainVe
ctor; | |
61 typedef HashMap<AtomicString, EventListenerAsyncCallChainVector> EventListen
erAsyncCallChainVectorHashMap; | |
62 | |
63 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu
tionContext) | 58 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu
tionContext) |
64 : ContextLifecycleObserver(executionContext) | 59 : ContextLifecycleObserver(executionContext) |
65 , m_tracker(tracker) | 60 , m_tracker(tracker) |
66 { | 61 { |
67 } | 62 } |
68 | 63 |
69 virtual void contextDestroyed() OVERRIDE | 64 virtual void contextDestroyed() OVERRIDE |
70 { | 65 { |
71 ASSERT(executionContext()); | 66 ASSERT(executionContext()); |
72 ExecutionContextData* self = m_tracker->m_executionContextDataMap.take(e
xecutionContext()); | 67 ExecutionContextData* self = m_tracker->m_executionContextDataMap.take(e
xecutionContext()); |
73 ASSERT(self == this); | 68 ASSERT(self == this); |
74 ContextLifecycleObserver::contextDestroyed(); | 69 ContextLifecycleObserver::contextDestroyed(); |
75 delete self; | 70 delete self; |
76 } | 71 } |
77 | 72 |
78 void addEventListenerData(EventTarget* eventTarget, const AtomicString& even
tType, const EventListenerAsyncCallChain& item) | |
79 { | |
80 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap>::iterato
r it = m_eventTargetCallChains.find(eventTarget); | |
81 EventListenerAsyncCallChainVectorHashMap* mapPtr; | |
82 if (it == m_eventTargetCallChains.end()) | |
83 mapPtr = &m_eventTargetCallChains.set(eventTarget, EventListenerAsyn
cCallChainVectorHashMap()).storedValue->value; | |
84 else | |
85 mapPtr = &it->value; | |
86 EventListenerAsyncCallChainVectorHashMap& map = *mapPtr; | |
87 EventListenerAsyncCallChainVectorHashMap::iterator it2 = map.find(eventT
ype); | |
88 if (it2 == map.end()) | |
89 map.set(eventType, EventListenerAsyncCallChainVector()).storedValue-
>value.append(item); | |
90 else | |
91 it2->value.append(item); | |
92 } | |
93 | |
94 void removeEventListenerData(EventTarget* eventTarget, const AtomicString& e
ventType, const RegisteredEventListener& item) | |
95 { | |
96 findEventListenerData(eventTarget, eventType, item, true); | |
97 } | |
98 | |
99 PassRefPtr<AsyncCallChain> findEventListenerData(EventTarget* eventTarget, c
onst AtomicString& eventType, const RegisteredEventListener& item, bool remove =
false) | |
100 { | |
101 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap>::iterato
r it = m_eventTargetCallChains.find(eventTarget); | |
102 if (it == m_eventTargetCallChains.end()) | |
103 return nullptr; | |
104 EventListenerAsyncCallChainVectorHashMap& map = it->value; | |
105 EventListenerAsyncCallChainVectorHashMap::iterator it2 = map.find(eventT
ype); | |
106 if (it2 == map.end()) | |
107 return nullptr; | |
108 RefPtr<AsyncCallChain> result; | |
109 EventListenerAsyncCallChainVector& vector = it2->value; | |
110 for (size_t i = 0; i < vector.size(); ++i) { | |
111 if (vector[i].first == item) { | |
112 result = vector[i].second; | |
113 if (remove) { | |
114 vector.remove(i); | |
115 if (vector.isEmpty()) | |
116 map.remove(it2); | |
117 if (map.isEmpty()) | |
118 m_eventTargetCallChains.remove(it); | |
119 } | |
120 break; | |
121 } | |
122 } | |
123 return result.release(); | |
124 } | |
125 | |
126 public: | 73 public: |
127 AsyncCallStackTracker* m_tracker; | 74 AsyncCallStackTracker* m_tracker; |
128 HashSet<int> m_intervalTimerIds; | 75 HashSet<int> m_intervalTimerIds; |
129 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; | 76 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; |
130 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; | 77 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; |
131 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap> m_eventTarge
tCallChains; | |
132 HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; | 78 HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; |
133 HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallCh
ains; | 79 HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallCh
ains; |
134 }; | 80 }; |
135 | 81 |
136 static XMLHttpRequest* toXmlHttpRequest(EventTarget* eventTarget) | 82 static XMLHttpRequest* toXmlHttpRequest(EventTarget* eventTarget) |
137 { | 83 { |
138 const AtomicString& interfaceName = eventTarget->interfaceName(); | 84 const AtomicString& interfaceName = eventTarget->interfaceName(); |
139 if (interfaceName == EventTargetNames::XMLHttpRequest) | 85 if (interfaceName == EventTargetNames::XMLHttpRequest) |
140 return static_cast<XMLHttpRequest*>(eventTarget); | 86 return static_cast<XMLHttpRequest*>(eventTarget); |
141 if (interfaceName == EventTargetNames::XMLHttpRequestUpload) | 87 if (interfaceName == EventTargetNames::XMLHttpRequestUpload) |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 ASSERT(context); | 189 ASSERT(context); |
244 ASSERT(isEnabled()); | 190 ASSERT(isEnabled()); |
245 ASSERT(callbackId > 0); | 191 ASSERT(callbackId > 0); |
246 ASSERT(!m_currentAsyncCallChain); | 192 ASSERT(!m_currentAsyncCallChain); |
247 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 193 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
248 setCurrentAsyncCallChain(data->m_animationFrameCallChains.take(callbackI
d)); | 194 setCurrentAsyncCallChain(data->m_animationFrameCallChains.take(callbackI
d)); |
249 else | 195 else |
250 setCurrentAsyncCallChain(nullptr); | 196 setCurrentAsyncCallChain(nullptr); |
251 } | 197 } |
252 | 198 |
253 void AsyncCallStackTracker::didAddEventListener(EventTarget* eventTarget, const
AtomicString& eventType, EventListener* listener, bool useCapture, const ScriptV
alue& callFrames) | |
254 { | |
255 ASSERT(eventTarget->executionContext()); | |
256 ASSERT(isEnabled()); | |
257 if (!validateCallFrames(callFrames) || toXmlHttpRequest(eventTarget)) | |
258 return; | |
259 | |
260 StringBuilder description; | |
261 description.append(eventTarget->interfaceName()); | |
262 if (!description.isEmpty()) | |
263 description.append("."); | |
264 if (listener->isAttribute()) { | |
265 description.append("on"); | |
266 description.append(eventType); | |
267 } else { | |
268 description.append("addEventListener(\""); | |
269 description.append(eventType); | |
270 description.append("\")"); | |
271 } | |
272 | |
273 ExecutionContextData* data = createContextDataIfNeeded(eventTarget->executio
nContext()); | |
274 data->addEventListenerData(eventTarget, eventType, std::make_pair(Registered
EventListener(listener, useCapture), createAsyncCallChain(description.toString()
, callFrames))); | |
275 } | |
276 | |
277 void AsyncCallStackTracker::didRemoveEventListener(EventTarget* eventTarget, con
st AtomicString& eventType, EventListener* listener, bool useCapture) | |
278 { | |
279 ASSERT(eventTarget->executionContext()); | |
280 ASSERT(isEnabled()); | |
281 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) | |
282 data->removeEventListenerData(eventTarget, eventType, RegisteredEventLis
tener(listener, useCapture)); | |
283 } | |
284 | |
285 void AsyncCallStackTracker::didRemoveAllEventListeners(EventTarget* eventTarget) | |
286 { | |
287 ASSERT(eventTarget->executionContext()); | |
288 ASSERT(isEnabled()); | |
289 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) | |
290 data->m_eventTargetCallChains.remove(eventTarget); | |
291 } | |
292 | |
293 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom
icString& eventType, EventListener* listener, bool useCapture) | 199 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom
icString& eventType, EventListener* listener, bool useCapture) |
294 { | 200 { |
295 ASSERT(eventTarget->executionContext()); | 201 ASSERT(eventTarget->executionContext()); |
296 ASSERT(isEnabled()); | 202 ASSERT(isEnabled()); |
297 if (XMLHttpRequest* xhr = toXmlHttpRequest(eventTarget)) { | 203 if (XMLHttpRequest* xhr = toXmlHttpRequest(eventTarget)) |
298 willHandleXHREvent(xhr, eventTarget, eventType); | 204 willHandleXHREvent(xhr, eventTarget, eventType); |
299 return; | |
300 } | |
301 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) | |
302 setCurrentAsyncCallChain(data->findEventListenerData(eventTarget, eventT
ype, RegisteredEventListener(listener, useCapture))); | |
303 else | 205 else |
304 setCurrentAsyncCallChain(nullptr); | 206 setCurrentAsyncCallChain(nullptr); |
305 } | 207 } |
306 | 208 |
307 void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue&
callFrames) | 209 void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue&
callFrames) |
308 { | 210 { |
309 ASSERT(xhr->executionContext()); | 211 ASSERT(xhr->executionContext()); |
310 ASSERT(isEnabled()); | 212 ASSERT(isEnabled()); |
311 if (!validateCallFrames(callFrames)) | 213 if (!validateCallFrames(callFrames)) |
312 return; | 214 return; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 { | 327 { |
426 m_currentAsyncCallChain.clear(); | 328 m_currentAsyncCallChain.clear(); |
427 m_nestedAsyncCallCount = 0; | 329 m_nestedAsyncCallCount = 0; |
428 ExecutionContextDataMap copy; | 330 ExecutionContextDataMap copy; |
429 m_executionContextDataMap.swap(copy); | 331 m_executionContextDataMap.swap(copy); |
430 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e
nd(); ++it) | 332 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e
nd(); ++it) |
431 delete it->value; | 333 delete it->value; |
432 } | 334 } |
433 | 335 |
434 } // namespace WebCore | 336 } // namespace WebCore |
OLD | NEW |