Chromium Code Reviews| 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 |