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 22 matching lines...) Expand all Loading... | |
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/dom/ExecutionContextTask.h" | 38 #include "core/dom/ExecutionContextTask.h" |
39 #include "core/events/Event.h" | 39 #include "core/events/Event.h" |
40 #include "core/events/EventTarget.h" | 40 #include "core/events/EventTarget.h" |
41 #include "core/xml/XMLHttpRequest.h" | 41 #include "core/xml/XMLHttpRequest.h" |
42 #include "core/xml/XMLHttpRequestUpload.h" | 42 #include "core/xml/XMLHttpRequestUpload.h" |
43 #include "platform/AsyncFileSystemCallbacks.h" | |
43 #include "wtf/text/StringBuilder.h" | 44 #include "wtf/text/StringBuilder.h" |
44 #include "wtf/text/StringHash.h" | 45 #include "wtf/text/StringHash.h" |
45 #include <v8.h> | 46 #include <v8.h> |
46 | 47 |
47 namespace { | 48 namespace { |
48 | 49 |
49 static const char setTimeoutName[] = "setTimeout"; | 50 static const char setTimeoutName[] = "setTimeout"; |
50 static const char setIntervalName[] = "setInterval"; | 51 static const char setIntervalName[] = "setInterval"; |
51 static const char requestAnimationFrameName[] = "requestAnimationFrame"; | 52 static const char requestAnimationFrameName[] = "requestAnimationFrame"; |
52 static const char xhrSendName[] = "XMLHttpRequest.send"; | 53 static const char xhrSendName[] = "XMLHttpRequest.send"; |
53 static const char enqueueMutationRecordName[] = "Mutation"; | 54 static const char enqueueMutationRecordName[] = "Mutation"; |
55 static const char fileSystemName[] = "FileSystem"; | |
54 | 56 |
55 } | 57 } |
56 | 58 |
57 namespace WebCore { | 59 namespace WebCore { |
58 | 60 |
59 class AsyncCallStackTracker::ExecutionContextData FINAL : public ContextLifecycl eObserver { | 61 class AsyncCallStackTracker::ExecutionContextData FINAL : public ContextLifecycl eObserver { |
60 WTF_MAKE_FAST_ALLOCATED; | 62 WTF_MAKE_FAST_ALLOCATED; |
61 public: | 63 public: |
62 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu tionContext) | 64 ExecutionContextData(AsyncCallStackTracker* tracker, ExecutionContext* execu tionContext) |
63 : ContextLifecycleObserver(executionContext) | 65 : ContextLifecycleObserver(executionContext) |
(...skipping 12 matching lines...) Expand all Loading... | |
76 | 78 |
77 public: | 79 public: |
78 AsyncCallStackTracker* m_tracker; | 80 AsyncCallStackTracker* m_tracker; |
79 HashSet<int> m_intervalTimerIds; | 81 HashSet<int> m_intervalTimerIds; |
80 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; | 82 HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; |
81 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; | 83 HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; |
82 HashMap<Event*, RefPtr<AsyncCallChain> > m_eventCallChains; | 84 HashMap<Event*, RefPtr<AsyncCallChain> > m_eventCallChains; |
83 HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; | 85 HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; |
84 HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallCh ains; | 86 HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallCh ains; |
85 HashMap<ExecutionContextTask*, RefPtr<AsyncCallChain> > m_executionContextTa skCallChains; | 87 HashMap<ExecutionContextTask*, RefPtr<AsyncCallChain> > m_executionContextTa skCallChains; |
88 HashMap<AsyncFileSystemCallbacks*, RefPtr<AsyncCallChain> > m_fileSystemCall Chains; | |
86 HashMap<String, RefPtr<AsyncCallChain> > m_v8AsyncTaskCallChains; | 89 HashMap<String, RefPtr<AsyncCallChain> > m_v8AsyncTaskCallChains; |
87 }; | 90 }; |
88 | 91 |
89 static XMLHttpRequest* toXmlHttpRequest(EventTarget* eventTarget) | 92 static XMLHttpRequest* toXmlHttpRequest(EventTarget* eventTarget) |
90 { | 93 { |
91 const AtomicString& interfaceName = eventTarget->interfaceName(); | 94 const AtomicString& interfaceName = eventTarget->interfaceName(); |
92 if (interfaceName == EventTargetNames::XMLHttpRequest) | 95 if (interfaceName == EventTargetNames::XMLHttpRequest) |
93 return static_cast<XMLHttpRequest*>(eventTarget); | 96 return static_cast<XMLHttpRequest*>(eventTarget); |
94 if (interfaceName == EventTargetNames::XMLHttpRequestUpload) | 97 if (interfaceName == EventTargetNames::XMLHttpRequestUpload) |
95 return static_cast<XMLHttpRequestUpload*>(eventTarget)->xmlHttpRequest() ; | 98 return static_cast<XMLHttpRequestUpload*>(eventTarget)->xmlHttpRequest() ; |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 void AsyncCallStackTracker::willPerformExecutionContextTask(ExecutionContext* co ntext, ExecutionContextTask* task) | 323 void AsyncCallStackTracker::willPerformExecutionContextTask(ExecutionContext* co ntext, ExecutionContextTask* task) |
321 { | 324 { |
322 ASSERT(context); | 325 ASSERT(context); |
323 ASSERT(isEnabled()); | 326 ASSERT(isEnabled()); |
324 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | 327 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) |
325 setCurrentAsyncCallChain(context, data->m_executionContextTaskCallChains .take(task)); | 328 setCurrentAsyncCallChain(context, data->m_executionContextTaskCallChains .take(task)); |
326 else | 329 else |
327 setCurrentAsyncCallChain(context, nullptr); | 330 setCurrentAsyncCallChain(context, nullptr); |
328 } | 331 } |
329 | 332 |
333 void AsyncCallStackTracker::didEnqueueAsyncFileSystemCallback(ExecutionContext* context, AsyncFileSystemCallbacks* callback, const ScriptValue& callFrames) | |
334 { | |
335 ASSERT(context); | |
336 ASSERT(isEnabled()); | |
337 if (!validateCallFrames(callFrames)) | |
338 return; | |
339 ExecutionContextData* data = createContextDataIfNeeded(context); | |
340 data->m_fileSystemCallChains.set(callback, createAsyncCallChain(fileSystemNa me, callFrames)); | |
341 } | |
342 | |
343 void AsyncCallStackTracker::didRemoveAsyncFileSystemCallback(ExecutionContext* c ontext, AsyncFileSystemCallbacks* callback) | |
344 { | |
345 ASSERT(context); | |
346 ASSERT(isEnabled()); | |
347 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) | |
348 data->m_fileSystemCallChains.remove(callback); | |
349 } | |
350 | |
351 void AsyncCallStackTracker::willHandleAsyncFileSystemCallback(ExecutionContext* context, AsyncFileSystemCallbacks* callback, bool hasMore) | |
352 { | |
353 ASSERT(context); | |
354 ASSERT(isEnabled()); | |
355 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) { | |
356 if (hasMore) | |
357 setCurrentAsyncCallChain(context, data->m_fileSystemCallChains.get(c allback)); | |
yurys
2014/07/14 14:55:54
style: consider extracting setCurrentAsyncCallChai
| |
358 else | |
359 setCurrentAsyncCallChain(context, data->m_fileSystemCallChains.take( callback)); | |
360 } else { | |
361 setCurrentAsyncCallChain(context, nullptr); | |
362 } | |
363 } | |
364 | |
330 static String makeV8AsyncTaskUniqueId(const String& eventName, int id) | 365 static String makeV8AsyncTaskUniqueId(const String& eventName, int id) |
331 { | 366 { |
332 StringBuilder builder; | 367 StringBuilder builder; |
333 builder.append(eventName); | 368 builder.append(eventName); |
334 builder.appendNumber(id); | 369 builder.appendNumber(id); |
335 return builder.toString(); | 370 return builder.toString(); |
336 } | 371 } |
337 | 372 |
338 void AsyncCallStackTracker::didEnqueueV8AsyncTask(ExecutionContext* context, con st String& eventName, int id, const ScriptValue& callFrames) | 373 void AsyncCallStackTracker::didEnqueueV8AsyncTask(ExecutionContext* context, con st String& eventName, int id, const ScriptValue& callFrames) |
339 { | 374 { |
(...skipping 13 matching lines...) Expand all Loading... | |
353 setCurrentAsyncCallChain(context, data->m_v8AsyncTaskCallChains.take(mak eV8AsyncTaskUniqueId(eventName, id))); | 388 setCurrentAsyncCallChain(context, data->m_v8AsyncTaskCallChains.take(mak eV8AsyncTaskUniqueId(eventName, id))); |
354 else | 389 else |
355 setCurrentAsyncCallChain(context, nullptr); | 390 setCurrentAsyncCallChain(context, nullptr); |
356 } | 391 } |
357 | 392 |
358 void AsyncCallStackTracker::didFireAsyncCall() | 393 void AsyncCallStackTracker::didFireAsyncCall() |
359 { | 394 { |
360 clearCurrentAsyncCallChain(); | 395 clearCurrentAsyncCallChain(); |
361 } | 396 } |
362 | 397 |
398 void AsyncCallStackTracker::willRescheduleAsyncCallChain() | |
399 { | |
400 ASSERT(isEnabled()); | |
401 if (!m_rescheduledAsyncCallChain) | |
402 m_rescheduleNextAsyncCallChain = true; | |
403 } | |
404 | |
405 void AsyncCallStackTracker::didRescheduleAsyncCallChain() | |
406 { | |
407 ASSERT(isEnabled()); | |
408 m_rescheduleNextAsyncCallChain = false; | |
409 m_rescheduledAsyncCallChain.clear(); | |
410 } | |
411 | |
363 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA syncCallChain(const String& description, const ScriptValue& callFrames) | 412 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA syncCallChain(const String& description, const ScriptValue& callFrames) |
364 { | 413 { |
414 // Check if we should propogate the async call stack chain. | |
415 if (m_rescheduledAsyncCallChain) | |
416 return m_rescheduledAsyncCallChain; | |
365 if (callFrames.isEmpty()) { | 417 if (callFrames.isEmpty()) { |
366 ASSERT(m_currentAsyncCallChain); | 418 ASSERT(m_currentAsyncCallChain); |
367 return m_currentAsyncCallChain; // Propogate async call stack chain. | 419 return m_currentAsyncCallChain; |
368 } | 420 } |
369 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr acker::AsyncCallChain()); | 421 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr acker::AsyncCallChain()); |
370 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); | 422 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1); |
371 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta ck(description, callFrames))); | 423 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta ck(description, callFrames))); |
372 return chain.release(); | 424 return chain.release(); |
373 } | 425 } |
374 | 426 |
375 void AsyncCallStackTracker::setCurrentAsyncCallChain(ExecutionContext* context, PassRefPtr<AsyncCallChain> chain) | 427 void AsyncCallStackTracker::setCurrentAsyncCallChain(ExecutionContext* context, PassRefPtr<AsyncCallChain> chain) |
376 { | 428 { |
429 if (m_rescheduleNextAsyncCallChain) { | |
430 m_rescheduleNextAsyncCallChain = false; | |
431 m_rescheduledAsyncCallChain = chain.get(); | |
432 } | |
377 if (V8RecursionScope::recursionLevel(toIsolate(context))) { | 433 if (V8RecursionScope::recursionLevel(toIsolate(context))) { |
378 if (m_currentAsyncCallChain) | 434 if (m_currentAsyncCallChain) |
379 ++m_nestedAsyncCallCount; | 435 ++m_nestedAsyncCallCount; |
380 } else { | 436 } else { |
381 // Current AsyncCallChain corresponds to the bottommost JS call frame. | 437 // Current AsyncCallChain corresponds to the bottommost JS call frame. |
382 m_currentAsyncCallChain = chain; | 438 m_currentAsyncCallChain = chain; |
383 m_nestedAsyncCallCount = m_currentAsyncCallChain ? 1 : 0; | 439 m_nestedAsyncCallCount = m_currentAsyncCallChain ? 1 : 0; |
384 } | 440 } |
385 } | 441 } |
386 | 442 |
387 void AsyncCallStackTracker::clearCurrentAsyncCallChain() | 443 void AsyncCallStackTracker::clearCurrentAsyncCallChain() |
388 { | 444 { |
389 if (!m_nestedAsyncCallCount) | 445 if (!m_nestedAsyncCallCount) |
390 return; | 446 return; |
391 --m_nestedAsyncCallCount; | 447 --m_nestedAsyncCallCount; |
392 if (!m_nestedAsyncCallCount) | 448 if (!m_nestedAsyncCallCount) |
393 m_currentAsyncCallChain.clear(); | 449 m_currentAsyncCallChain.clear(); |
394 } | 450 } |
395 | 451 |
396 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth) | 452 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth) |
397 { | 453 { |
398 while (chain->m_callStacks.size() > maxDepth) | 454 while (chain->m_callStacks.size() > maxDepth) |
399 chain->m_callStacks.removeLast(); | 455 chain->m_callStacks.removeLast(); |
400 } | 456 } |
401 | 457 |
402 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) | 458 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames) |
403 { | 459 { |
404 return !callFrames.isEmpty() || m_currentAsyncCallChain; | 460 return !callFrames.isEmpty() || m_currentAsyncCallChain || m_rescheduledAsyn cCallChain; |
405 } | 461 } |
406 | 462 |
407 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex tDataIfNeeded(ExecutionContext* context) | 463 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex tDataIfNeeded(ExecutionContext* context) |
408 { | 464 { |
409 ExecutionContextData* data = m_executionContextDataMap.get(context); | 465 ExecutionContextData* data = m_executionContextDataMap.get(context); |
410 if (!data) { | 466 if (!data) { |
411 data = new AsyncCallStackTracker::ExecutionContextData(this, context); | 467 data = new AsyncCallStackTracker::ExecutionContextData(this, context); |
412 m_executionContextDataMap.set(context, data); | 468 m_executionContextDataMap.set(context, data); |
413 } | 469 } |
414 return data; | 470 return data; |
415 } | 471 } |
416 | 472 |
417 void AsyncCallStackTracker::clear() | 473 void AsyncCallStackTracker::clear() |
418 { | 474 { |
419 m_currentAsyncCallChain.clear(); | 475 m_currentAsyncCallChain.clear(); |
420 m_nestedAsyncCallCount = 0; | 476 m_nestedAsyncCallCount = 0; |
477 m_rescheduleNextAsyncCallChain = false; | |
478 m_rescheduledAsyncCallChain.clear(); | |
421 ExecutionContextDataMap copy; | 479 ExecutionContextDataMap copy; |
422 m_executionContextDataMap.swap(copy); | 480 m_executionContextDataMap.swap(copy); |
423 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e nd(); ++it) | 481 for (ExecutionContextDataMap::const_iterator it = copy.begin(); it != copy.e nd(); ++it) |
424 delete it->value; | 482 delete it->value; |
425 } | 483 } |
426 | 484 |
427 } // namespace WebCore | 485 } // namespace WebCore |
OLD | NEW |