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 21 matching lines...) Expand all Loading... |
32 #include "core/inspector/AsyncCallStackTracker.h" | 32 #include "core/inspector/AsyncCallStackTracker.h" |
33 | 33 |
34 #include "bindings/core/v8/V8Binding.h" | 34 #include "bindings/core/v8/V8Binding.h" |
35 #include "bindings/core/v8/V8RecursionScope.h" | 35 #include "bindings/core/v8/V8RecursionScope.h" |
36 #include "core/dom/ContextLifecycleObserver.h" | 36 #include "core/dom/ContextLifecycleObserver.h" |
37 #include "core/dom/ExecutionContext.h" | 37 #include "core/dom/ExecutionContext.h" |
38 #include "core/events/Event.h" | 38 #include "core/events/Event.h" |
39 #include "core/events/EventTarget.h" | 39 #include "core/events/EventTarget.h" |
40 #include "core/xml/XMLHttpRequest.h" | 40 #include "core/xml/XMLHttpRequest.h" |
41 #include "core/xml/XMLHttpRequestUpload.h" | 41 #include "core/xml/XMLHttpRequestUpload.h" |
42 #include "wtf/text/AtomicStringHash.h" | |
43 #include "wtf/text/StringBuilder.h" | 42 #include "wtf/text/StringBuilder.h" |
| 43 #include "wtf/text/StringHash.h" |
44 #include <v8.h> | 44 #include <v8.h> |
45 | 45 |
46 namespace { | 46 namespace { |
47 | 47 |
48 static const char setTimeoutName[] = "setTimeout"; | 48 static const char setTimeoutName[] = "setTimeout"; |
49 static const char setIntervalName[] = "setInterval"; | 49 static const char setIntervalName[] = "setInterval"; |
50 static const char requestAnimationFrameName[] = "requestAnimationFrame"; | 50 static const char requestAnimationFrameName[] = "requestAnimationFrame"; |
51 static const char xhrSendName[] = "XMLHttpRequest.send"; | 51 static const char xhrSendName[] = "XMLHttpRequest.send"; |
52 static const char enqueueMutationRecordName[] = "Mutation"; | 52 static const char enqueueMutationRecordName[] = "Mutation"; |
53 | 53 |
(...skipping 20 matching lines...) Expand all Loading... |
74 } | 74 } |
75 | 75 |
76 public: | 76 public: |
77 AsyncCallStackTracker* m_tracker; | 77 AsyncCallStackTracker* m_tracker; |
78 HashSet<int> m_intervalTimerIds; | 78 HashSet<int> m_intervalTimerIds; |
79 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; | 79 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; |
80 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; | 80 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; |
81 HashMap<Event*, RefPtr<AsyncCallChain> > m_eventCallChains; | 81 HashMap<Event*, RefPtr<AsyncCallChain> > m_eventCallChains; |
82 HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; | 82 HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; |
83 HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallCh
ains; | 83 HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallCh
ains; |
| 84 HashMap<String, RefPtr<AsyncCallChain> > m_v8AsyncTaskCallChains; |
84 }; | 85 }; |
85 | 86 |
86 static XMLHttpRequest* toXmlHttpRequest(EventTarget* eventTarget) | 87 static XMLHttpRequest* toXmlHttpRequest(EventTarget* eventTarget) |
87 { | 88 { |
88 const AtomicString& interfaceName = eventTarget->interfaceName(); | 89 const AtomicString& interfaceName = eventTarget->interfaceName(); |
89 if (interfaceName == EventTargetNames::XMLHttpRequest) | 90 if (interfaceName == EventTargetNames::XMLHttpRequest) |
90 return static_cast<XMLHttpRequest*>(eventTarget); | 91 return static_cast<XMLHttpRequest*>(eventTarget); |
91 if (interfaceName == EventTargetNames::XMLHttpRequestUpload) | 92 if (interfaceName == EventTargetNames::XMLHttpRequestUpload) |
92 return static_cast<XMLHttpRequestUpload*>(eventTarget)->xmlHttpRequest()
; | 93 return static_cast<XMLHttpRequestUpload*>(eventTarget)->xmlHttpRequest()
; |
93 return 0; | 94 return 0; |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 void AsyncCallStackTracker::willDeliverMutationRecords(ExecutionContext* context
, MutationObserver* observer) | 290 void AsyncCallStackTracker::willDeliverMutationRecords(ExecutionContext* context
, MutationObserver* observer) |
290 { | 291 { |
291 ASSERT(context); | 292 ASSERT(context); |
292 ASSERT(isEnabled()); | 293 ASSERT(isEnabled()); |
293 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 294 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
294 setCurrentAsyncCallChain(context, data->m_mutationObserverCallChains.tak
e(observer)); | 295 setCurrentAsyncCallChain(context, data->m_mutationObserverCallChains.tak
e(observer)); |
295 else | 296 else |
296 setCurrentAsyncCallChain(context, nullptr); | 297 setCurrentAsyncCallChain(context, nullptr); |
297 } | 298 } |
298 | 299 |
| 300 static String makeV8AsyncTaskUniqueId(const String& eventName, int id) |
| 301 { |
| 302 StringBuilder builder; |
| 303 builder.append(eventName); |
| 304 builder.appendNumber(id); |
| 305 return builder.toString(); |
| 306 } |
| 307 |
| 308 void AsyncCallStackTracker::didEnqueueV8AsyncTask(ExecutionContext* context, con
st String& eventName, int id, const ScriptValue& callFrames) |
| 309 { |
| 310 ASSERT(context); |
| 311 ASSERT(isEnabled()); |
| 312 if (!validateCallFrames(callFrames)) |
| 313 return; |
| 314 ExecutionContextData* data = createContextDataIfNeeded(context); |
| 315 data->m_v8AsyncTaskCallChains.set(makeV8AsyncTaskUniqueId(eventName, id), cr
eateAsyncCallChain(eventName, callFrames)); |
| 316 } |
| 317 |
| 318 void AsyncCallStackTracker::willHandleV8AsyncTask(ExecutionContext* context, con
st String& eventName, int id) |
| 319 { |
| 320 ASSERT(context); |
| 321 ASSERT(isEnabled()); |
| 322 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
| 323 setCurrentAsyncCallChain(context, data->m_v8AsyncTaskCallChains.take(mak
eV8AsyncTaskUniqueId(eventName, id))); |
| 324 else |
| 325 setCurrentAsyncCallChain(context, nullptr); |
| 326 } |
| 327 |
299 void AsyncCallStackTracker::didFireAsyncCall() | 328 void AsyncCallStackTracker::didFireAsyncCall() |
300 { | 329 { |
301 clearCurrentAsyncCallChain(); | 330 clearCurrentAsyncCallChain(); |
302 } | 331 } |
303 | 332 |
304 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA
syncCallChain(const String& description, const ScriptValue& callFrames) | 333 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA
syncCallChain(const String& description, const ScriptValue& callFrames) |
305 { | 334 { |
| 335 if (callFrames.isEmpty()) { |
| 336 ASSERT(m_currentAsyncCallChain); |
| 337 return m_currentAsyncCallChain; // Propogate async call stack chain. |
| 338 } |
306 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC
allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr
acker::AsyncCallChain()); | 339 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC
allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr
acker::AsyncCallChain()); |
307 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); | 340 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); |
308 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta
ck(description, callFrames))); | 341 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta
ck(description, callFrames))); |
309 return chain.release(); | 342 return chain.release(); |
310 } | 343 } |
311 | 344 |
312 void AsyncCallStackTracker::setCurrentAsyncCallChain(ExecutionContext* context,
PassRefPtr<AsyncCallChain> chain) | 345 void AsyncCallStackTracker::setCurrentAsyncCallChain(ExecutionContext* context,
PassRefPtr<AsyncCallChain> chain) |
313 { | 346 { |
314 if (V8RecursionScope::recursionLevel(toIsolate(context))) { | 347 if (V8RecursionScope::recursionLevel(toIsolate(context))) { |
315 if (m_currentAsyncCallChain) | 348 if (m_currentAsyncCallChain) |
(...skipping 15 matching lines...) Expand all Loading... |
331 } | 364 } |
332 | 365 |
333 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain,
unsigned maxDepth) | 366 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain,
unsigned maxDepth) |
334 { | 367 { |
335 while (chain->m_callStacks.size() > maxDepth) | 368 while (chain->m_callStacks.size() > maxDepth) |
336 chain->m_callStacks.removeLast(); | 369 chain->m_callStacks.removeLast(); |
337 } | 370 } |
338 | 371 |
339 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) | 372 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) |
340 { | 373 { |
341 return !callFrames.isEmpty(); | 374 return !callFrames.isEmpty() || m_currentAsyncCallChain; |
342 } | 375 } |
343 | 376 |
344 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex
tDataIfNeeded(ExecutionContext* context) | 377 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex
tDataIfNeeded(ExecutionContext* context) |
345 { | 378 { |
346 ExecutionContextData* data = m_executionContextDataMap.get(context); | 379 ExecutionContextData* data = m_executionContextDataMap.get(context); |
347 if (!data) { | 380 if (!data) { |
348 data = new AsyncCallStackTracker::ExecutionContextData(this, context); | 381 data = new AsyncCallStackTracker::ExecutionContextData(this, context); |
349 m_executionContextDataMap.set(context, data); | 382 m_executionContextDataMap.set(context, data); |
350 } | 383 } |
351 return data; | 384 return data; |
352 } | 385 } |
353 | 386 |
354 void AsyncCallStackTracker::clear() | 387 void AsyncCallStackTracker::clear() |
355 { | 388 { |
356 m_currentAsyncCallChain.clear(); | 389 m_currentAsyncCallChain.clear(); |
357 m_nestedAsyncCallCount = 0; | 390 m_nestedAsyncCallCount = 0; |
358 ExecutionContextDataMap copy; | 391 ExecutionContextDataMap copy; |
359 m_executionContextDataMap.swap(copy); | 392 m_executionContextDataMap.swap(copy); |
360 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e
nd(); ++it) | 393 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e
nd(); ++it) |
361 delete it->value; | 394 delete it->value; |
362 } | 395 } |
363 | 396 |
364 } // namespace WebCore | 397 } // namespace WebCore |
OLD | NEW |