blob: e2c69d841c4f3bf2431097fed3da2b20ff36d277 [file] [log] [blame]
// 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(InspectorDebuggerAgent* 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(InspectorDebuggerAgent* 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
InspectorDebuggerAgent::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(InspectorDebuggerAgent::unknownAsyncOperationId);
}
}
} // namespace blink