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) |
| 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; |
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 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 { | 213 { |
162 ASSERT(context); | 214 ASSERT(context); |
163 if (!isEnabled()) | 215 if (!isEnabled()) |
164 return; | 216 return; |
165 ASSERT(callbackId > 0); | 217 ASSERT(callbackId > 0); |
166 ASSERT(!m_currentAsyncCallChain); | 218 ASSERT(!m_currentAsyncCallChain); |
167 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 219 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
168 m_currentAsyncCallChain = data->m_animationFrameCallChains.take(callback
Id); | 220 m_currentAsyncCallChain = data->m_animationFrameCallChains.take(callback
Id); |
169 } | 221 } |
170 | 222 |
| 223 void AsyncCallStackTracker::didAddEventListener(EventTarget* eventTarget, const
AtomicString& eventType, EventListener* listener, bool useCapture, const ScriptV
alue& callFrames) |
| 224 { |
| 225 ASSERT(eventTarget->executionContext()); |
| 226 ASSERT(isEnabled()); |
| 227 if (!validateCallFrames(callFrames)) |
| 228 return; |
| 229 |
| 230 StringBuilder description; |
| 231 description.append(eventTarget->interfaceName()); |
| 232 if (!description.isEmpty()) |
| 233 description.append("."); |
| 234 if (listener->isAttribute()) { |
| 235 description.append("on"); |
| 236 description.append(eventType); |
| 237 } else { |
| 238 description.append("addEventListener(\""); |
| 239 description.append(eventType); |
| 240 description.append("\")"); |
| 241 } |
| 242 |
| 243 ExecutionContextData* data = createContextDataIfNeeded(eventTarget->executio
nContext()); |
| 244 data->add(eventTarget, eventType, std::make_pair(RegisteredEventListener(lis
tener, useCapture), createAsyncCallChain(description.toString(), callFrames))); |
| 245 } |
| 246 |
| 247 void AsyncCallStackTracker::didRemoveEventListener(EventTarget* eventTarget, con
st AtomicString& eventType, EventListener* listener, bool useCapture) |
| 248 { |
| 249 ASSERT(eventTarget->executionContext()); |
| 250 if (!isEnabled()) |
| 251 return; |
| 252 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) |
| 253 data->remove(eventTarget, eventType, RegisteredEventListener(listener, u
seCapture)); |
| 254 } |
| 255 |
| 256 void AsyncCallStackTracker::didRemoveAllEventListeners(EventTarget* eventTarget) |
| 257 { |
| 258 ASSERT(eventTarget->executionContext()); |
| 259 if (!isEnabled()) |
| 260 return; |
| 261 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) |
| 262 data->m_eventTargetCallChains.remove(eventTarget); |
| 263 } |
| 264 |
| 265 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom
icString& eventType, EventListener* listener, bool useCapture) |
| 266 { |
| 267 ASSERT(eventTarget->executionContext()); |
| 268 if (!isEnabled()) |
| 269 return; |
| 270 // FIXME: Handle events being fired synchronously right after they are added
. |
| 271 // ASSERT(!m_currentAsyncCallChain); |
| 272 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) |
| 273 m_currentAsyncCallChain = data->get(eventTarget, eventType, RegisteredEv
entListener(listener, useCapture)); |
| 274 } |
| 275 |
171 void AsyncCallStackTracker::didFireAsyncCall() | 276 void AsyncCallStackTracker::didFireAsyncCall() |
172 { | 277 { |
173 m_currentAsyncCallChain = 0; | 278 m_currentAsyncCallChain = 0; |
174 } | 279 } |
175 | 280 |
176 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA
syncCallChain(const String& description, const ScriptValue& callFrames) | 281 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA
syncCallChain(const String& description, const ScriptValue& callFrames) |
177 { | 282 { |
178 ASSERT(isEnabled()); | 283 ASSERT(isEnabled()); |
179 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC
allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr
acker::AsyncCallChain()); | 284 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC
allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr
acker::AsyncCallChain()); |
180 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); | 285 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 { | 319 { |
215 m_currentAsyncCallChain = 0; | 320 m_currentAsyncCallChain = 0; |
216 Vector<ExecutionContextData*> contextsData; | 321 Vector<ExecutionContextData*> contextsData; |
217 copyValuesToVector(m_executionContextDataMap, contextsData); | 322 copyValuesToVector(m_executionContextDataMap, contextsData); |
218 m_executionContextDataMap.clear(); | 323 m_executionContextDataMap.clear(); |
219 for (Vector<ExecutionContextData*>::const_iterator it = contextsData.begin()
; it != contextsData.end(); ++it) | 324 for (Vector<ExecutionContextData*>::const_iterator it = contextsData.begin()
; it != contextsData.end(); ++it) |
220 delete *it; | 325 delete *it; |
221 } | 326 } |
222 | 327 |
223 } // namespace WebCore | 328 } // namespace WebCore |
OLD | NEW |