Index: third_party/WebKit/Source/core/inspector/V8AsyncCallTracker.cpp |
diff --git a/third_party/WebKit/Source/core/inspector/V8AsyncCallTracker.cpp b/third_party/WebKit/Source/core/inspector/V8AsyncCallTracker.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8e68a5daf6278a1082944439a8144929ef4374e5 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/inspector/V8AsyncCallTracker.cpp |
@@ -0,0 +1,143 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+#include "core/inspector/V8AsyncCallTracker.h" |
+ |
+#include "bindings/core/v8/V8PerContextData.h" |
+#include "core/inspector/AsyncOperationMap.h" |
+#include "platform/heap/Handle.h" |
+#include "wtf/HashMap.h" |
+#include "wtf/text/StringBuilder.h" |
+#include "wtf/text/StringHash.h" |
+#include "wtf/text/WTFString.h" |
+ |
+namespace blink { |
+ |
+namespace { |
+ |
+static const char v8AsyncTaskEventEnqueue[] = "enqueue"; |
+static const char v8AsyncTaskEventWillHandle[] = "willHandle"; |
+static const char v8AsyncTaskEventDidHandle[] = "didHandle"; |
+ |
+} |
+ |
+class V8AsyncCallTracker::V8ContextAsyncOperations final : public NoBaseWillBeGarbageCollectedFinalized<V8AsyncCallTracker::V8ContextAsyncOperations> { |
+ WTF_MAKE_NONCOPYABLE(V8ContextAsyncOperations); |
+public: |
+ explicit V8ContextAsyncOperations(V8DebuggerAgent* debuggerAgent) |
+ : m_v8AsyncOperations(debuggerAgent) |
+ { |
+ } |
+ |
+ ~V8ContextAsyncOperations() |
+ { |
+ ASSERT(m_v8AsyncOperations.hasBeenDisposed()); |
+ } |
+ |
+ void dispose() |
+ { |
+ // FIXME: get rid of the dispose method and this class altogether once AsyncOperationMap is always allocated on C++ heap. |
+ m_v8AsyncOperations.dispose(); |
+ } |
+ |
+ DEFINE_INLINE_TRACE() |
+ { |
+#if ENABLE(OILPAN) |
+ visitor->trace(m_v8AsyncOperations); |
+#endif |
+ } |
+ |
+ AsyncOperationMap<String> m_v8AsyncOperations; |
+}; |
+ |
+static String makeV8AsyncTaskUniqueId(const String& eventName, int id) |
+{ |
+ StringBuilder builder; |
+ builder.append(eventName); |
+ builder.append(" -> "); |
+ builder.appendNumber(id); |
+ return builder.toString(); |
+} |
+ |
+V8AsyncCallTracker::V8AsyncCallTracker(V8DebuggerAgent* debuggerAgent) : m_debuggerAgent(debuggerAgent) |
+{ |
+ m_debuggerAgent->addAsyncCallTrackingListener(this); |
+} |
+ |
+V8AsyncCallTracker::~V8AsyncCallTracker() |
+{ |
+ ASSERT(m_contextAsyncOperationMap.isEmpty()); |
+#if !ENABLE(OILPAN) |
+ m_debuggerAgent->removeAsyncCallTrackingListener(this); |
+#endif |
+} |
+ |
+DEFINE_TRACE(V8AsyncCallTracker) |
+{ |
+#if ENABLE(OILPAN) |
+ visitor->trace(m_contextAsyncOperationMap); |
+ visitor->trace(m_debuggerAgent); |
+#endif |
+ V8DebuggerAgent::AsyncCallTrackingListener::trace(visitor); |
+} |
+ |
+void V8AsyncCallTracker::asyncCallTrackingStateChanged(bool) |
+{ |
+} |
+ |
+void V8AsyncCallTracker::resetAsyncOperations() |
+{ |
+ for (auto& it : m_contextAsyncOperationMap) { |
+ it.key->removeObserver(this); |
+ it.value->dispose(); |
+ } |
+ m_contextAsyncOperationMap.clear(); |
+} |
+ |
+void V8AsyncCallTracker::willDisposeScriptState(ScriptState* state) |
+{ |
+ m_contextAsyncOperationMap.remove(state); |
+} |
+ |
+void V8AsyncCallTracker::didReceiveV8AsyncTaskEvent(ScriptState* state, const String& eventType, const String& eventName, int id) |
+{ |
+ ASSERT(m_debuggerAgent->trackingAsyncCalls()); |
+ if (eventType == v8AsyncTaskEventEnqueue) |
+ didEnqueueV8AsyncTask(state, eventName, id); |
+ else if (eventType == v8AsyncTaskEventWillHandle) |
+ willHandleV8AsyncTask(state, eventName, id); |
+ else if (eventType == v8AsyncTaskEventDidHandle) |
+ m_debuggerAgent->traceAsyncCallbackCompleted(); |
+ else |
+ ASSERT_NOT_REACHED(); |
+} |
+ |
+void V8AsyncCallTracker::didEnqueueV8AsyncTask(ScriptState* state, const String& eventName, int id) |
+{ |
+ ASSERT(state); |
+ ASSERT(m_debuggerAgent->trackingAsyncCalls()); |
+ int operationId = m_debuggerAgent->traceAsyncOperationStarting(eventName); |
+ if (!operationId) |
+ return; |
+ V8ContextAsyncOperations* contextCallChains = m_contextAsyncOperationMap.get(state); |
+ if (!contextCallChains) |
+ contextCallChains = m_contextAsyncOperationMap.set(state, adoptPtrWillBeNoop(new V8ContextAsyncOperations(m_debuggerAgent))).storedValue->value.get(); |
+ contextCallChains->m_v8AsyncOperations.set(makeV8AsyncTaskUniqueId(eventName, id), operationId); |
+} |
+ |
+void V8AsyncCallTracker::willHandleV8AsyncTask(ScriptState* state, const String& eventName, int id) |
+{ |
+ ASSERT(state); |
+ ASSERT(m_debuggerAgent->trackingAsyncCalls()); |
+ if (V8ContextAsyncOperations* contextCallChains = m_contextAsyncOperationMap.get(state)) { |
+ String taskId = makeV8AsyncTaskUniqueId(eventName, id); |
+ m_debuggerAgent->traceAsyncCallbackStarting(contextCallChains->m_v8AsyncOperations.get(taskId)); |
+ contextCallChains->m_v8AsyncOperations.remove(taskId); |
+ } else { |
+ m_debuggerAgent->traceAsyncCallbackStarting(V8DebuggerAgent::unknownAsyncOperationId); |
+ } |
+} |
+ |
+} // namespace blink |