Add V8Inspector::uniqueDebuggerId method

This method returns the unique debugger ID for a v8::Context (i.e. the
V8DebuggerID), serialized to a pair of int64_ts.

Bug: v8:12528
Change-Id: Ib2cdda73447f8233f9afb773fed4a634d4618aef
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3369124
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Alex Turner <alexmt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78958}
This commit is contained in:
Alex Turner 2022-02-03 17:16:45 -05:00 committed by V8 LUCI CQ
parent 9e9d9142d6
commit e3ca1f1a73
12 changed files with 91 additions and 34 deletions

View File

@ -23,6 +23,10 @@ class Value;
namespace v8_inspector {
namespace internal {
class V8DebuggerId;
} // namespace internal
namespace protocol {
namespace Debugger {
namespace API {
@ -106,6 +110,30 @@ class V8_EXPORT V8ContextInfo {
V8ContextInfo& operator=(const V8ContextInfo&) = delete;
};
// This debugger id tries to be unique by generating two random
// numbers, which should most likely avoid collisions.
// Debugger id has a 1:1 mapping to context group. It is used to
// attribute stack traces to a particular debugging, when doing any
// cross-debugger operations (e.g. async step in).
// See also Runtime.UniqueDebuggerId in the protocol.
class V8_EXPORT V8DebuggerId {
public:
V8DebuggerId(const V8DebuggerId&) = default;
V8DebuggerId& operator=(const V8DebuggerId&) = default;
std::unique_ptr<StringBuffer> toString() const;
bool isValid() const;
std::pair<int64_t, int64_t> pair() const;
private:
friend class internal::V8DebuggerId;
V8DebuggerId() = default;
explicit V8DebuggerId(std::pair<int64_t, int64_t>);
int64_t m_first = 0;
int64_t m_second = 0;
};
class V8_EXPORT V8StackTrace {
public:
virtual StringView firstNonEmptySourceURL() const = 0;
@ -276,6 +304,7 @@ class V8_EXPORT V8Inspector {
virtual void contextDestroyed(v8::Local<v8::Context>) = 0;
virtual void resetContextGroup(int contextGroupId) = 0;
virtual v8::MaybeLocal<v8::Context> contextById(int contextId) = 0;
virtual V8DebuggerId uniqueDebuggerId(int contextId) = 0;
// Various instrumentation.
virtual void idleStarted() = 0;

View File

@ -56,7 +56,7 @@ InspectedContext::InspectedContext(V8InspectorImpl* inspector,
m_origin(toString16(info.origin)),
m_humanReadableName(toString16(info.humanReadableName)),
m_auxData(toString16(info.auxData)),
m_uniqueId(V8DebuggerId::generate(inspector)) {
m_uniqueId(internal::V8DebuggerId::generate(inspector)) {
v8::debug::SetContextId(info.context, contextId);
m_weakCallbackData =
new WeakCallbackData(this, m_inspector, m_contextGroupId, m_contextId);

View File

@ -43,7 +43,7 @@ class InspectedContext {
int contextGroupId() const { return m_contextGroupId; }
String16 origin() const { return m_origin; }
String16 humanReadableName() const { return m_humanReadableName; }
V8DebuggerId uniqueId() const { return m_uniqueId; }
internal::V8DebuggerId uniqueId() const { return m_uniqueId; }
String16 auxData() const { return m_auxData; }
bool isReported(int sessionId) const;
@ -73,7 +73,7 @@ class InspectedContext {
const String16 m_origin;
const String16 m_humanReadableName;
const String16 m_auxData;
const V8DebuggerId m_uniqueId;
const internal::V8DebuggerId m_uniqueId;
std::unordered_set<int> m_reportedSessionIds;
std::unordered_map<int, std::unique_ptr<InjectedScript>> m_injectedScripts;
WeakCallbackData* m_weakCallbackData;

View File

@ -845,9 +845,10 @@ Response V8DebuggerAgentImpl::getStackTrace(
int64_t id = inStackTraceId->getId().toInteger64(&isOk);
if (!isOk) return Response::ServerError("Invalid stack trace id");
V8DebuggerId debuggerId;
internal::V8DebuggerId debuggerId;
if (inStackTraceId->hasDebuggerId()) {
debuggerId = V8DebuggerId(inStackTraceId->getDebuggerId(String16()));
debuggerId =
internal::V8DebuggerId(inStackTraceId->getDebuggerId(String16()));
} else {
debuggerId = m_debugger->debuggerIdFor(m_session->contextGroupId());
}
@ -1521,7 +1522,8 @@ V8DebuggerAgentImpl::currentExternalStackTrace() {
if (externalParent.IsInvalid()) return nullptr;
return protocol::Runtime::StackTraceId::create()
.setId(stackTraceIdToString(externalParent.id))
.setDebuggerId(V8DebuggerId(externalParent.debugger_id).toString())
.setDebuggerId(
internal::V8DebuggerId(externalParent.debugger_id).toString())
.build();
}

View File

@ -5,6 +5,7 @@
#include "src/inspector/v8-debugger-id.h"
#include "src/debug/debug-interface.h"
#include "src/inspector/string-util.h"
#include "src/inspector/v8-inspector-impl.h"
namespace v8_inspector {
@ -12,6 +13,22 @@ namespace v8_inspector {
V8DebuggerId::V8DebuggerId(std::pair<int64_t, int64_t> pair)
: m_first(pair.first), m_second(pair.second) {}
std::unique_ptr<StringBuffer> V8DebuggerId::toString() const {
return StringBufferFrom(String16::fromInteger64(m_first) + "." +
String16::fromInteger64(m_second));
}
bool V8DebuggerId::isValid() const { return m_first || m_second; }
std::pair<int64_t, int64_t> V8DebuggerId::pair() const {
return std::make_pair(m_first, m_second);
}
namespace internal {
V8DebuggerId::V8DebuggerId(std::pair<int64_t, int64_t> pair)
: m_debugger_id(pair) {}
// static
V8DebuggerId V8DebuggerId::generate(V8InspectorImpl* inspector) {
return V8DebuggerId(std::make_pair(inspector->generateUniqueId(),
@ -27,19 +44,18 @@ V8DebuggerId::V8DebuggerId(const String16& debuggerId) {
if (!ok) return;
int64_t second = debuggerId.substring(pos + 1).toInteger64(&ok);
if (!ok) return;
m_first = first;
m_second = second;
m_debugger_id = v8_inspector::V8DebuggerId(std::make_pair(first, second));
}
String16 V8DebuggerId::toString() const {
return String16::fromInteger64(m_first) + "." +
String16::fromInteger64(m_second);
return toString16(m_debugger_id.toString()->string());
}
bool V8DebuggerId::isValid() const { return m_first || m_second; }
bool V8DebuggerId::isValid() const { return m_debugger_id.isValid(); }
std::pair<int64_t, int64_t> V8DebuggerId::pair() const {
return std::make_pair(m_first, m_second);
return m_debugger_id.pair();
}
} // namespace internal
} // namespace v8_inspector

View File

@ -7,38 +7,35 @@
#include <utility>
#include "include/v8-inspector.h"
#include "src/base/macros.h"
#include "src/inspector/protocol/Forward.h"
namespace v8_inspector {
class V8InspectorImpl;
// This debugger id tries to be unique by generating two random
// numbers, which should most likely avoid collisions.
// Debugger id has a 1:1 mapping to context group. It is used to
// attribute stack traces to a particular debugging, when doing any
// cross-debugger operations (e.g. async step in).
// See also Runtime.UniqueDebuggerId in the protocol.
namespace internal {
class V8DebuggerId {
public:
V8DebuggerId() = default;
explicit V8DebuggerId(std::pair<int64_t, int64_t>);
explicit V8DebuggerId(const String16&);
V8DebuggerId(const V8DebuggerId&) V8_NOEXCEPT = default;
~V8DebuggerId() = default;
V8DebuggerId& operator=(const V8DebuggerId&) V8_NOEXCEPT = default;
static V8DebuggerId generate(V8InspectorImpl*);
v8_inspector::V8DebuggerId toV8DebuggerId() const { return m_debugger_id; }
String16 toString() const;
bool isValid() const;
std::pair<int64_t, int64_t> pair() const;
private:
int64_t m_first = 0;
int64_t m_second = 0;
v8_inspector::V8DebuggerId m_debugger_id;
};
} // namespace internal
} // namespace v8_inspector
#endif // V8_INSPECTOR_V8_DEBUGGER_ID_H_

View File

@ -1159,10 +1159,11 @@ void V8Debugger::setMaxAsyncTaskStacksForTest(int limit) {
m_maxAsyncCallStacks = limit;
}
V8DebuggerId V8Debugger::debuggerIdFor(int contextGroupId) {
internal::V8DebuggerId V8Debugger::debuggerIdFor(int contextGroupId) {
auto it = m_contextGroupIdToDebuggerId.find(contextGroupId);
if (it != m_contextGroupIdToDebuggerId.end()) return it->second;
V8DebuggerId debuggerId = V8DebuggerId::generate(m_inspector);
internal::V8DebuggerId debuggerId =
internal::V8DebuggerId::generate(m_inspector);
m_contextGroupIdToDebuggerId.insert(
it, std::make_pair(contextGroupId, debuggerId));
return debuggerId;

View File

@ -124,7 +124,7 @@ class V8Debugger : public v8::debug::DebugDelegate,
void setMaxAsyncTaskStacksForTest(int limit);
void dumpAsyncTaskStacksStateForTest();
V8DebuggerId debuggerIdFor(int contextGroupId);
internal::V8DebuggerId debuggerIdFor(int contextGroupId);
std::shared_ptr<AsyncStackTrace> stackTraceFor(int contextGroupId,
const V8StackTraceId& id);
@ -283,7 +283,7 @@ class V8Debugger : public v8::debug::DebugDelegate,
StackTraceIdToStackTrace m_storedStackTraces;
uintptr_t m_lastStackTraceId = 0;
std::unordered_map<int, V8DebuggerId> m_contextGroupIdToDebuggerId;
std::unordered_map<int, internal::V8DebuggerId> m_contextGroupIdToDebuggerId;
std::unique_ptr<TerminateExecutionCallback> m_terminateExecutionCallback;
};

View File

@ -44,6 +44,7 @@
#include "src/inspector/v8-console-message.h"
#include "src/inspector/v8-console.h"
#include "src/inspector/v8-debugger-agent-impl.h"
#include "src/inspector/v8-debugger-id.h"
#include "src/inspector/v8-debugger.h"
#include "src/inspector/v8-inspector-session-impl.h"
#include "src/inspector/v8-profiler-agent-impl.h"
@ -83,7 +84,8 @@ int V8InspectorImpl::contextGroupId(int contextId) const {
return it != m_contextIdToGroupIdMap.end() ? it->second : 0;
}
int V8InspectorImpl::resolveUniqueContextId(V8DebuggerId uniqueId) const {
int V8InspectorImpl::resolveUniqueContextId(
internal::V8DebuggerId uniqueId) const {
auto it = m_uniqueIdToContextId.find(uniqueId.pair());
return it == m_uniqueIdToContextId.end() ? 0 : it->second;
}
@ -180,6 +182,13 @@ v8::MaybeLocal<v8::Context> V8InspectorImpl::contextById(int contextId) {
return context ? context->context() : v8::MaybeLocal<v8::Context>();
}
V8DebuggerId V8InspectorImpl::uniqueDebuggerId(int contextId) {
InspectedContext* context = getContext(contextId);
internal::V8DebuggerId unique_id;
if (context) unique_id = context->uniqueId();
return unique_id.toV8DebuggerId();
}
void V8InspectorImpl::contextCreated(const V8ContextInfo& info) {
int contextId = ++m_lastContextId;
auto* context = new InspectedContext(this, info, contextId);

View File

@ -67,7 +67,7 @@ class V8InspectorImpl : public V8Inspector {
int contextGroupId(v8::Local<v8::Context>) const;
int contextGroupId(int contextId) const;
uint64_t isolateId() const { return m_isolateId; }
int resolveUniqueContextId(V8DebuggerId uniqueId) const;
int resolveUniqueContextId(internal::V8DebuggerId uniqueId) const;
v8::MaybeLocal<v8::Value> compileAndRunInternalScript(v8::Local<v8::Context>,
v8::Local<v8::String>);
@ -84,6 +84,7 @@ class V8InspectorImpl : public V8Inspector {
void contextCreated(const V8ContextInfo&) override;
void contextDestroyed(v8::Local<v8::Context>) override;
v8::MaybeLocal<v8::Context> contextById(int contextId) override;
V8DebuggerId uniqueDebuggerId(int contextId) override;
void contextCollected(int contextGroupId, int contextId);
void resetContextGroup(int contextGroupId) override;
void idleStarted() override;

View File

@ -217,7 +217,7 @@ Response ensureContext(V8InspectorImpl* inspector, int contextGroupId,
}
*contextId = executionContextId.fromJust();
} else if (uniqueContextId.isJust()) {
V8DebuggerId uniqueId(uniqueContextId.fromJust());
internal::V8DebuggerId uniqueId(uniqueContextId.fromJust());
if (!uniqueId.isValid())
return Response::InvalidParams("invalid uniqueContextId");
int id = inspector->resolveUniqueContextId(uniqueId);

View File

@ -107,7 +107,8 @@ std::unique_ptr<protocol::Runtime::StackTrace> buildInspectorObjectCommon(
stackTrace->setParentId(
protocol::Runtime::StackTraceId::create()
.setId(stackTraceIdToString(externalParent.id))
.setDebuggerId(V8DebuggerId(externalParent.debugger_id).toString())
.setDebuggerId(
internal::V8DebuggerId(externalParent.debugger_id).toString())
.build());
}
return stackTrace;
@ -115,7 +116,8 @@ std::unique_ptr<protocol::Runtime::StackTrace> buildInspectorObjectCommon(
} // namespace
V8StackTraceId::V8StackTraceId() : id(0), debugger_id(V8DebuggerId().pair()) {}
V8StackTraceId::V8StackTraceId()
: id(0), debugger_id(internal::V8DebuggerId().pair()) {}
V8StackTraceId::V8StackTraceId(uintptr_t id,
const std::pair<int64_t, int64_t> debugger_id)
@ -127,7 +129,7 @@ V8StackTraceId::V8StackTraceId(uintptr_t id,
: id(id), debugger_id(debugger_id), should_pause(should_pause) {}
V8StackTraceId::V8StackTraceId(StringView json)
: id(0), debugger_id(V8DebuggerId().pair()) {
: id(0), debugger_id(internal::V8DebuggerId().pair()) {
if (json.length() == 0) return;
std::vector<uint8_t> cbor;
if (json.is8Bit()) {
@ -146,7 +148,7 @@ V8StackTraceId::V8StackTraceId(StringView json)
int64_t parsedId = s.toInteger64(&isOk);
if (!isOk || !parsedId) return;
if (!dict->getString(kDebuggerId, &s)) return;
V8DebuggerId debuggerId(s);
internal::V8DebuggerId debuggerId(s);
if (!debuggerId.isValid()) return;
if (!dict->getBoolean(kShouldPause, &should_pause)) return;
id = parsedId;
@ -159,7 +161,7 @@ std::unique_ptr<StringBuffer> V8StackTraceId::ToString() {
if (IsInvalid()) return nullptr;
auto dict = protocol::DictionaryValue::create();
dict->setString(kId, String16::fromInteger64(id));
dict->setString(kDebuggerId, V8DebuggerId(debugger_id).toString());
dict->setString(kDebuggerId, internal::V8DebuggerId(debugger_id).toString());
dict->setBoolean(kShouldPause, should_pause);
std::vector<uint8_t> json;
v8_crdtp::json::ConvertCBORToJSON(v8_crdtp::SpanFrom(dict->Serialize()),