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 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 |