| 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 static const char promiseResolved[] = "Promise.resolve"; | 50 static const char promiseResolved[] = "Promise.resolve"; |
| 52 static const char promiseRejected[] = "Promise.reject"; | 51 static const char promiseRejected[] = "Promise.reject"; |
| 53 | 52 |
| 54 } | 53 } |
| 55 | 54 |
| 56 namespace WebCore { | 55 namespace WebCore { |
| 57 | 56 |
| 58 class AsyncCallStackTracker::ExecutionContextData FINAL : public ContextLifecycl
eObserver { | 57 class AsyncCallStackTracker::ExecutionContextData FINAL : public ContextLifecycl
eObserver { |
| 59 WTF_MAKE_FAST_ALLOCATED; | 58 WTF_MAKE_FAST_ALLOCATED; |
| 60 public: | 59 public: |
| 61 typedef std::pair<RegisteredEventListener, RefPtr<AsyncCallChain> > EventLis
tenerAsyncCallChain; | |
| 62 typedef Vector<EventListenerAsyncCallChain, 1> EventListenerAsyncCallChainVe
ctor; | |
| 63 typedef HashMap<AtomicString, EventListenerAsyncCallChainVector> EventListen
erAsyncCallChainVectorHashMap; | |
| 64 | |
| 65 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu
tionContext) | 60 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu
tionContext) |
| 66 : ContextLifecycleObserver(executionContext) | 61 : ContextLifecycleObserver(executionContext) |
| 67 , m_tracker(tracker) | 62 , m_tracker(tracker) |
| 68 { | 63 { |
| 69 } | 64 } |
| 70 | 65 |
| 71 virtual void contextDestroyed() OVERRIDE | 66 virtual void contextDestroyed() OVERRIDE |
| 72 { | 67 { |
| 73 ASSERT(executionContext()); | 68 ASSERT(executionContext()); |
| 74 ExecutionContextData* self = m_tracker->m_executionContextDataMap.take(e
xecutionContext()); | 69 ExecutionContextData* self = m_tracker->m_executionContextDataMap.take(e
xecutionContext()); |
| 75 ASSERT(self == this); | 70 ASSERT(self == this); |
| 76 ContextLifecycleObserver::contextDestroyed(); | 71 ContextLifecycleObserver::contextDestroyed(); |
| 77 delete self; | 72 delete self; |
| 78 } | 73 } |
| 79 | 74 |
| 80 void addEventListenerData(EventTarget* eventTarget, const AtomicString& even
tType, const EventListenerAsyncCallChain& item) | |
| 81 { | |
| 82 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap>::iterato
r it = m_eventTargetCallChains.find(eventTarget); | |
| 83 EventListenerAsyncCallChainVectorHashMap* mapPtr; | |
| 84 if (it == m_eventTargetCallChains.end()) | |
| 85 mapPtr = &m_eventTargetCallChains.set(eventTarget, EventListenerAsyn
cCallChainVectorHashMap()).storedValue->value; | |
| 86 else | |
| 87 mapPtr = &it->value; | |
| 88 EventListenerAsyncCallChainVectorHashMap& map = *mapPtr; | |
| 89 EventListenerAsyncCallChainVectorHashMap::iterator it2 = map.find(eventT
ype); | |
| 90 if (it2 == map.end()) | |
| 91 map.set(eventType, EventListenerAsyncCallChainVector()).storedValue-
>value.append(item); | |
| 92 else | |
| 93 it2->value.append(item); | |
| 94 } | |
| 95 | |
| 96 void removeEventListenerData(EventTarget* eventTarget, const AtomicString& e
ventType, const RegisteredEventListener& item) | |
| 97 { | |
| 98 findEventListenerData(eventTarget, eventType, item, true); | |
| 99 } | |
| 100 | |
| 101 PassRefPtr<AsyncCallChain> findEventListenerData(EventTarget* eventTarget, c
onst AtomicString& eventType, const RegisteredEventListener& item, bool remove =
false) | |
| 102 { | |
| 103 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap>::iterato
r it = m_eventTargetCallChains.find(eventTarget); | |
| 104 if (it == m_eventTargetCallChains.end()) | |
| 105 return nullptr; | |
| 106 EventListenerAsyncCallChainVectorHashMap& map = it->value; | |
| 107 EventListenerAsyncCallChainVectorHashMap::iterator it2 = map.find(eventT
ype); | |
| 108 if (it2 == map.end()) | |
| 109 return nullptr; | |
| 110 RefPtr<AsyncCallChain> result; | |
| 111 EventListenerAsyncCallChainVector& vector = it2->value; | |
| 112 for (size_t i = 0; i < vector.size(); ++i) { | |
| 113 if (vector[i].first == item) { | |
| 114 result = vector[i].second; | |
| 115 if (remove) { | |
| 116 vector.remove(i); | |
| 117 if (vector.isEmpty()) | |
| 118 map.remove(it2); | |
| 119 if (map.isEmpty()) | |
| 120 m_eventTargetCallChains.remove(it); | |
| 121 } | |
| 122 break; | |
| 123 } | |
| 124 } | |
| 125 return result.release(); | |
| 126 } | |
| 127 | |
| 128 public: | 75 public: |
| 129 AsyncCallStackTracker* m_tracker; | 76 AsyncCallStackTracker* m_tracker; |
| 130 HashSet<int> m_intervalTimerIds; | 77 HashSet<int> m_intervalTimerIds; |
| 131 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; | 78 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; |
| 132 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; | 79 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; |
| 133 HashMap<EventTarget*, EventListenerAsyncCallChainVectorHashMap> m_eventTarge
tCallChains; | |
| 134 HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; | 80 HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; |
| 135 HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallCh
ains; | 81 HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallCh
ains; |
| 136 HashMap<ExecutionContextTask*, RefPtr<AsyncCallChain> > m_promiseTaskCallCha
ins; | 82 HashMap<ExecutionContextTask*, RefPtr<AsyncCallChain> > m_promiseTaskCallCha
ins; |
| 137 }; | 83 }; |
| 138 | 84 |
| 139 static XMLHttpRequest* toXmlHttpRequest(EventTarget* eventTarget) | 85 static XMLHttpRequest* toXmlHttpRequest(EventTarget* eventTarget) |
| 140 { | 86 { |
| 141 const AtomicString& interfaceName = eventTarget->interfaceName(); | 87 const AtomicString& interfaceName = eventTarget->interfaceName(); |
| 142 if (interfaceName == EventTargetNames::XMLHttpRequest) | 88 if (interfaceName == EventTargetNames::XMLHttpRequest) |
| 143 return static_cast<XMLHttpRequest*>(eventTarget); | 89 return static_cast<XMLHttpRequest*>(eventTarget); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 ASSERT(context); | 192 ASSERT(context); |
| 247 ASSERT(isEnabled()); | 193 ASSERT(isEnabled()); |
| 248 ASSERT(callbackId > 0); | 194 ASSERT(callbackId > 0); |
| 249 ASSERT(!m_currentAsyncCallChain); | 195 ASSERT(!m_currentAsyncCallChain); |
| 250 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 196 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
| 251 setCurrentAsyncCallChain(data->m_animationFrameCallChains.take(callbackI
d)); | 197 setCurrentAsyncCallChain(data->m_animationFrameCallChains.take(callbackI
d)); |
| 252 else | 198 else |
| 253 setCurrentAsyncCallChain(nullptr); | 199 setCurrentAsyncCallChain(nullptr); |
| 254 } | 200 } |
| 255 | 201 |
| 256 void AsyncCallStackTracker::didAddEventListener(EventTarget* eventTarget, const
AtomicString& eventType, EventListener* listener, bool useCapture, const ScriptV
alue& callFrames) | |
| 257 { | |
| 258 ASSERT(eventTarget->executionContext()); | |
| 259 ASSERT(isEnabled()); | |
| 260 if (!validateCallFrames(callFrames) || toXmlHttpRequest(eventTarget)) | |
| 261 return; | |
| 262 | |
| 263 StringBuilder description; | |
| 264 description.append(eventTarget->interfaceName()); | |
| 265 if (!description.isEmpty()) | |
| 266 description.append("."); | |
| 267 if (listener->isAttribute()) { | |
| 268 description.append("on"); | |
| 269 description.append(eventType); | |
| 270 } else { | |
| 271 description.append("addEventListener(\""); | |
| 272 description.append(eventType); | |
| 273 description.append("\")"); | |
| 274 } | |
| 275 | |
| 276 ExecutionContextData* data = createContextDataIfNeeded(eventTarget->executio
nContext()); | |
| 277 data->addEventListenerData(eventTarget, eventType, std::make_pair(Registered
EventListener(listener, useCapture), createAsyncCallChain(description.toString()
, callFrames))); | |
| 278 } | |
| 279 | |
| 280 void AsyncCallStackTracker::didRemoveEventListener(EventTarget* eventTarget, con
st AtomicString& eventType, EventListener* listener, bool useCapture) | |
| 281 { | |
| 282 ASSERT(eventTarget->executionContext()); | |
| 283 ASSERT(isEnabled()); | |
| 284 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) | |
| 285 data->removeEventListenerData(eventTarget, eventType, RegisteredEventLis
tener(listener, useCapture)); | |
| 286 } | |
| 287 | |
| 288 void AsyncCallStackTracker::didRemoveAllEventListeners(EventTarget* eventTarget) | |
| 289 { | |
| 290 ASSERT(eventTarget->executionContext()); | |
| 291 ASSERT(isEnabled()); | |
| 292 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) | |
| 293 data->m_eventTargetCallChains.remove(eventTarget); | |
| 294 } | |
| 295 | |
| 296 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom
icString& eventType, EventListener* listener, bool useCapture) | 202 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const Atom
icString& eventType, EventListener* listener, bool useCapture) |
| 297 { | 203 { |
| 298 ASSERT(eventTarget->executionContext()); | 204 ASSERT(eventTarget->executionContext()); |
| 299 ASSERT(isEnabled()); | 205 ASSERT(isEnabled()); |
| 300 if (XMLHttpRequest* xhr = toXmlHttpRequest(eventTarget)) { | 206 if (XMLHttpRequest* xhr = toXmlHttpRequest(eventTarget)) |
| 301 willHandleXHREvent(xhr, eventTarget, eventType); | 207 willHandleXHREvent(xhr, eventTarget, eventType); |
| 302 return; | |
| 303 } | |
| 304 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->
executionContext())) | |
| 305 setCurrentAsyncCallChain(data->findEventListenerData(eventTarget, eventT
ype, RegisteredEventListener(listener, useCapture))); | |
| 306 else | 208 else |
| 307 setCurrentAsyncCallChain(nullptr); | 209 setCurrentAsyncCallChain(nullptr); |
| 308 } | 210 } |
| 309 | 211 |
| 310 void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue&
callFrames) | 212 void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue&
callFrames) |
| 311 { | 213 { |
| 312 ASSERT(xhr->executionContext()); | 214 ASSERT(xhr->executionContext()); |
| 313 ASSERT(isEnabled()); | 215 ASSERT(isEnabled()); |
| 314 if (!validateCallFrames(callFrames)) | 216 if (!validateCallFrames(callFrames)) |
| 315 return; | 217 return; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 { | 354 { |
| 453 m_currentAsyncCallChain.clear(); | 355 m_currentAsyncCallChain.clear(); |
| 454 m_nestedAsyncCallCount = 0; | 356 m_nestedAsyncCallCount = 0; |
| 455 ExecutionContextDataMap copy; | 357 ExecutionContextDataMap copy; |
| 456 m_executionContextDataMap.swap(copy); | 358 m_executionContextDataMap.swap(copy); |
| 457 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e
nd(); ++it) | 359 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e
nd(); ++it) |
| 458 delete it->value; | 360 delete it->value; |
| 459 } | 361 } |
| 460 | 362 |
| 461 } // namespace WebCore | 363 } // namespace WebCore |
| OLD | NEW |