aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/inspector/v8-debugger.cc
diff options
context:
space:
mode:
authorMyles Borins <mylesborins@google.com>2017-08-01 11:36:44 -0500
committerMyles Borins <mylesborins@google.com>2017-08-01 15:23:15 -0500
commit0a66b223e149a841669bfad5598e4254589730cb (patch)
tree5ec050f7f78aafbf5b1e0e50d639fb843141e162 /deps/v8/src/inspector/v8-debugger.cc
parent1782b3836ba58ef0da6b687f2bb970c0bd8199ad (diff)
downloadandroid-node-v8-0a66b223e149a841669bfad5598e4254589730cb.tar.gz
android-node-v8-0a66b223e149a841669bfad5598e4254589730cb.tar.bz2
android-node-v8-0a66b223e149a841669bfad5598e4254589730cb.zip
deps: update V8 to 6.0.286.52
PR-URL: https://github.com/nodejs/node/pull/14004 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Diffstat (limited to 'deps/v8/src/inspector/v8-debugger.cc')
-rw-r--r--deps/v8/src/inspector/v8-debugger.cc298
1 files changed, 212 insertions, 86 deletions
diff --git a/deps/v8/src/inspector/v8-debugger.cc b/deps/v8/src/inspector/v8-debugger.cc
index 87c864cd38..86a48401a6 100644
--- a/deps/v8/src/inspector/v8-debugger.cc
+++ b/deps/v8/src/inspector/v8-debugger.cc
@@ -21,9 +21,6 @@ namespace v8_inspector {
namespace {
-// Based on DevTools frontend measurement, with asyncCallStackDepth = 4,
-// average async call stack tail requires ~1 Kb. Let's reserve ~ 128 Mb
-// for async stacks.
static const int kMaxAsyncTaskStacks = 128 * 1024;
inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) {
@@ -32,11 +29,8 @@ inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) {
V8DebuggerAgentImpl* agentForScript(V8InspectorImpl* inspector,
v8::Local<v8::debug::Script> script) {
- v8::Local<v8::Value> contextData;
- if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) {
- return nullptr;
- }
- int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value());
+ int contextId;
+ if (!script->ContextId().To(&contextId)) return nullptr;
int contextGroupId = inspector->contextGroupId(contextId);
if (!contextGroupId) return nullptr;
return inspector->enabledDebuggerAgentForGroup(contextGroupId);
@@ -136,6 +130,17 @@ v8::MaybeLocal<v8::Object> generatorObjectLocation(
suspendedLocation.GetColumnNumber());
}
+template <typename Map>
+void cleanupExpiredWeakPointers(Map& map) {
+ for (auto it = map.begin(); it != map.end();) {
+ if (it->second.expired()) {
+ it = map.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
} // namespace
static bool inLiveEditScope = false;
@@ -164,10 +169,8 @@ V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector)
m_inspector(inspector),
m_enableCount(0),
m_breakpointsActivated(true),
- m_runningNestedMessageLoop(false),
m_ignoreScriptParsedEventsCounter(0),
m_maxAsyncCallStacks(kMaxAsyncTaskStacks),
- m_lastTaskId(0),
m_maxAsyncCallStackDepth(0),
m_pauseOnExceptionsState(v8::debug::NoBreakOnException),
m_wasmTranslation(isolate) {}
@@ -191,6 +194,7 @@ void V8Debugger::disable() {
if (--m_enableCount) return;
DCHECK(enabled());
clearBreakpoints();
+ clearContinueToLocation();
m_debuggerScript.Reset();
m_debuggerContext.Reset();
allAsyncTasksCanceled();
@@ -212,10 +216,12 @@ void V8Debugger::getCompiledScripts(
for (size_t i = 0; i < scripts.Size(); ++i) {
v8::Local<v8::debug::Script> script = scripts.Get(i);
if (!script->WasCompiled()) continue;
- v8::Local<v8::Value> contextData;
- if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32())
+ if (script->IsEmbedded()) {
+ result.push_back(V8DebuggerScript::Create(m_isolate, script, false));
continue;
- int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value());
+ }
+ int contextId;
+ if (!script->ContextId().To(&contextId)) continue;
if (m_inspector->contextGroupId(contextId) != contextGroupId) continue;
result.push_back(V8DebuggerScript::Create(m_isolate, script, false));
}
@@ -358,7 +364,8 @@ bool V8Debugger::breakProgram(int targetContextGroupId) {
return m_inspector->enabledDebuggerAgentForGroup(targetContextGroupId);
}
-void V8Debugger::continueProgram() {
+void V8Debugger::continueProgram(int targetContextGroupId) {
+ if (m_pausedContextGroupId != targetContextGroupId) return;
if (isPaused()) m_inspector->client()->quitMessageLoopOnPause();
m_pausedContext.Clear();
m_executionState.Clear();
@@ -370,7 +377,7 @@ void V8Debugger::stepIntoStatement(int targetContextGroupId) {
DCHECK(targetContextGroupId);
m_targetContextGroupId = targetContextGroupId;
v8::debug::PrepareStep(m_isolate, v8::debug::StepIn);
- continueProgram();
+ continueProgram(targetContextGroupId);
}
void V8Debugger::stepOverStatement(int targetContextGroupId) {
@@ -379,7 +386,7 @@ void V8Debugger::stepOverStatement(int targetContextGroupId) {
DCHECK(targetContextGroupId);
m_targetContextGroupId = targetContextGroupId;
v8::debug::PrepareStep(m_isolate, v8::debug::StepNext);
- continueProgram();
+ continueProgram(targetContextGroupId);
}
void V8Debugger::stepOutOfFunction(int targetContextGroupId) {
@@ -388,7 +395,7 @@ void V8Debugger::stepOutOfFunction(int targetContextGroupId) {
DCHECK(targetContextGroupId);
m_targetContextGroupId = targetContextGroupId;
v8::debug::PrepareStep(m_isolate, v8::debug::StepOut);
- continueProgram();
+ continueProgram(targetContextGroupId);
}
void V8Debugger::scheduleStepIntoAsync(
@@ -405,6 +412,58 @@ void V8Debugger::scheduleStepIntoAsync(
m_stepIntoAsyncCallback = std::move(callback);
}
+Response V8Debugger::continueToLocation(
+ int targetContextGroupId,
+ std::unique_ptr<protocol::Debugger::Location> location,
+ const String16& targetCallFrames) {
+ DCHECK(isPaused());
+ DCHECK(!m_executionState.IsEmpty());
+ DCHECK(targetContextGroupId);
+ m_targetContextGroupId = targetContextGroupId;
+ ScriptBreakpoint breakpoint(location->getScriptId(),
+ location->getLineNumber(),
+ location->getColumnNumber(0), String16());
+ int lineNumber = 0;
+ int columnNumber = 0;
+ m_continueToLocationBreakpointId =
+ setBreakpoint(breakpoint, &lineNumber, &columnNumber);
+ if (!m_continueToLocationBreakpointId.isEmpty()) {
+ m_continueToLocationTargetCallFrames = targetCallFrames;
+ if (m_continueToLocationTargetCallFrames !=
+ protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any) {
+ m_continueToLocationStack = captureStackTrace(true);
+ DCHECK(m_continueToLocationStack);
+ }
+ continueProgram(targetContextGroupId);
+ // TODO(kozyatinskiy): Return actual line and column number.
+ return Response::OK();
+ } else {
+ return Response::Error("Cannot continue to specified location");
+ }
+}
+
+bool V8Debugger::shouldContinueToCurrentLocation() {
+ if (m_continueToLocationTargetCallFrames ==
+ protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any) {
+ return true;
+ }
+ std::unique_ptr<V8StackTraceImpl> currentStack = captureStackTrace(true);
+ if (m_continueToLocationTargetCallFrames ==
+ protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Current) {
+ return m_continueToLocationStack->isEqualIgnoringTopFrame(
+ currentStack.get());
+ }
+ return true;
+}
+
+void V8Debugger::clearContinueToLocation() {
+ if (m_continueToLocationBreakpointId.isEmpty()) return;
+ removeBreakpoint(m_continueToLocationBreakpointId);
+ m_continueToLocationBreakpointId = String16();
+ m_continueToLocationTargetCallFrames = String16();
+ m_continueToLocationStack.reset();
+}
+
Response V8Debugger::setScriptSource(
const String16& sourceID, v8::Local<v8::String> newSource, bool dryRun,
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails,
@@ -560,11 +619,17 @@ void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext,
breakpointIds.push_back(String16::fromInteger(
hitBreakpointNumber->Int32Value(debuggerContext()).FromJust()));
}
+ if (breakpointIds.size() == 1 &&
+ breakpointIds[0] == m_continueToLocationBreakpointId) {
+ v8::Context::Scope contextScope(pausedContext);
+ if (!shouldContinueToCurrentLocation()) return;
+ }
}
+ clearContinueToLocation();
m_pausedContext = pausedContext;
m_executionState = executionState;
- m_runningNestedMessageLoop = true;
+ m_pausedContextGroupId = contextGroupId;
agent->didPause(InspectedContext::contextId(pausedContext), exception,
breakpointIds, isPromiseRejection, isUncaught,
m_scheduledOOMBreak);
@@ -576,7 +641,7 @@ void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext,
CHECK(!context.IsEmpty() &&
context != v8::debug::GetDebugContext(m_isolate));
m_inspector->client()->runMessageLoopOnPause(groupId);
- m_runningNestedMessageLoop = false;
+ m_pausedContextGroupId = 0;
}
// The agent may have been removed in the nested loop.
agent = m_inspector->enabledDebuggerAgentForGroup(groupId);
@@ -643,8 +708,7 @@ bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
end);
}
-void V8Debugger::PromiseEventOccurred(v8::Local<v8::Context> context,
- v8::debug::PromiseDebugActionType type,
+void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
int id, int parentId,
bool createdByUser) {
// Async task events from Promises are given misaligned pointers to prevent
@@ -655,10 +719,7 @@ void V8Debugger::PromiseEventOccurred(v8::Local<v8::Context> context,
switch (type) {
case v8::debug::kDebugPromiseCreated:
asyncTaskCreatedForStack(task, parentTask);
- if (createdByUser && parentTask) {
- v8::Context::Scope contextScope(context);
- asyncTaskCandidateForStepping(task);
- }
+ if (createdByUser && parentTask) asyncTaskCandidateForStepping(task);
break;
case v8::debug::kDebugEnqueueAsyncFunction:
asyncTaskScheduledForStack("async function", task, true);
@@ -669,10 +730,6 @@ void V8Debugger::PromiseEventOccurred(v8::Local<v8::Context> context,
case v8::debug::kDebugEnqueuePromiseReject:
asyncTaskScheduledForStack("Promise.reject", task, true);
break;
- case v8::debug::kDebugPromiseCollected:
- asyncTaskCanceledForStack(task);
- asyncTaskCanceledForStepping(task);
- break;
case v8::debug::kDebugWillHandle:
asyncTaskStartedForStack(task);
asyncTaskStartedForStepping(task);
@@ -684,9 +741,16 @@ void V8Debugger::PromiseEventOccurred(v8::Local<v8::Context> context,
}
}
-V8StackTraceImpl* V8Debugger::currentAsyncCallChain() {
- if (!m_currentStacks.size()) return nullptr;
- return m_currentStacks.back().get();
+std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncParent() {
+ // TODO(kozyatinskiy): implement creation chain as parent without hack.
+ if (!m_currentAsyncCreation.empty() && m_currentAsyncCreation.back()) {
+ return m_currentAsyncCreation.back();
+ }
+ return m_currentAsyncParent.empty() ? nullptr : m_currentAsyncParent.back();
+}
+
+std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncCreation() {
+ return nullptr;
}
void V8Debugger::compileDebuggerScript() {
@@ -827,8 +891,8 @@ v8::MaybeLocal<v8::Array> V8Debugger::internalProperties(
}
std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace(
- v8::Local<v8::StackTrace> stackTrace) {
- return V8StackTraceImpl::create(this, currentContextGroupId(), stackTrace,
+ v8::Local<v8::StackTrace> v8StackTrace) {
+ return V8StackTraceImpl::create(this, currentContextGroupId(), v8StackTrace,
V8StackTraceImpl::maxCallStackSizeToCapture);
}
@@ -849,31 +913,19 @@ void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) {
if (!maxAsyncCallStackDepth) allAsyncTasksCanceled();
}
-void V8Debugger::registerAsyncTaskIfNeeded(void* task) {
- if (m_taskToId.find(task) != m_taskToId.end()) return;
-
- int id = ++m_lastTaskId;
- m_taskToId[task] = id;
- m_idToTask[id] = task;
- if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) {
- void* taskToRemove = m_idToTask.begin()->second;
- asyncTaskCanceledForStack(taskToRemove);
- }
-}
-
void V8Debugger::asyncTaskCreatedForStack(void* task, void* parentTask) {
if (!m_maxAsyncCallStackDepth) return;
if (parentTask) m_parentTask[task] = parentTask;
v8::HandleScope scope(m_isolate);
- // We don't need to pass context group id here because we get this callback
- // from V8 for promise events only.
- // Passing one as maxStackSize forces no async chain for the new stack and
- // allows us to not grow exponentially.
- std::unique_ptr<V8StackTraceImpl> creationStack =
- V8StackTraceImpl::capture(this, 0, 1, String16());
- if (creationStack && !creationStack->isEmpty()) {
- m_asyncTaskCreationStacks[task] = std::move(creationStack);
- registerAsyncTaskIfNeeded(task);
+ std::shared_ptr<AsyncStackTrace> asyncCreation =
+ AsyncStackTrace::capture(this, currentContextGroupId(), String16(),
+ V8StackTraceImpl::maxCallStackSizeToCapture);
+ // Passing one as maxStackSize forces no async chain for the new stack.
+ if (asyncCreation && !asyncCreation->isEmpty()) {
+ m_asyncTaskCreationStacks[task] = asyncCreation;
+ m_allAsyncStacks.push_back(std::move(asyncCreation));
+ ++m_asyncStacksCount;
+ collectOldAsyncStacksIfNeeded();
}
}
@@ -902,13 +954,15 @@ void V8Debugger::asyncTaskScheduledForStack(const String16& taskName,
void* task, bool recurring) {
if (!m_maxAsyncCallStackDepth) return;
v8::HandleScope scope(m_isolate);
- std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture(
- this, currentContextGroupId(),
- V8StackTraceImpl::maxCallStackSizeToCapture, taskName);
- if (chain) {
- m_asyncTaskStacks[task] = std::move(chain);
+ std::shared_ptr<AsyncStackTrace> asyncStack =
+ AsyncStackTrace::capture(this, currentContextGroupId(), taskName,
+ V8StackTraceImpl::maxCallStackSizeToCapture);
+ if (asyncStack) {
+ m_asyncTaskStacks[task] = asyncStack;
if (recurring) m_recurringTasks.insert(task);
- registerAsyncTaskIfNeeded(task);
+ m_allAsyncStacks.push_back(std::move(asyncStack));
+ ++m_asyncStacksCount;
+ collectOldAsyncStacksIfNeeded();
}
}
@@ -918,18 +972,10 @@ void V8Debugger::asyncTaskCanceledForStack(void* task) {
m_recurringTasks.erase(task);
m_parentTask.erase(task);
m_asyncTaskCreationStacks.erase(task);
- auto it = m_taskToId.find(task);
- if (it == m_taskToId.end()) return;
- m_idToTask.erase(it->second);
- m_taskToId.erase(it);
}
void V8Debugger::asyncTaskStartedForStack(void* task) {
if (!m_maxAsyncCallStackDepth) return;
- m_currentTasks.push_back(task);
- auto parentIt = m_parentTask.find(task);
- AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(
- parentIt == m_parentTask.end() ? task : parentIt->second);
// Needs to support following order of events:
// - asyncTaskScheduled
// <-- attached here -->
@@ -937,25 +983,40 @@ void V8Debugger::asyncTaskStartedForStack(void* task) {
// - asyncTaskCanceled <-- canceled before finished
// <-- async stack requested here -->
// - asyncTaskFinished
- std::unique_ptr<V8StackTraceImpl> stack;
- if (stackIt != m_asyncTaskStacks.end() && stackIt->second)
- stack = stackIt->second->cloneImpl();
+ m_currentTasks.push_back(task);
+ auto parentIt = m_parentTask.find(task);
+ AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(
+ parentIt == m_parentTask.end() ? task : parentIt->second);
+ if (stackIt != m_asyncTaskStacks.end()) {
+ m_currentAsyncParent.push_back(stackIt->second.lock());
+ } else {
+ m_currentAsyncParent.emplace_back();
+ }
auto itCreation = m_asyncTaskCreationStacks.find(task);
- if (stack && itCreation != m_asyncTaskCreationStacks.end()) {
- stack->setCreation(itCreation->second->cloneImpl());
+ if (itCreation != m_asyncTaskCreationStacks.end()) {
+ m_currentAsyncCreation.push_back(itCreation->second.lock());
+ // TODO(kozyatinskiy): implement it without hack.
+ if (m_currentAsyncParent.back()) {
+ m_currentAsyncCreation.back()->setDescription(
+ m_currentAsyncParent.back()->description());
+ m_currentAsyncParent.back().reset();
+ }
+ } else {
+ m_currentAsyncCreation.emplace_back();
}
- m_currentStacks.push_back(std::move(stack));
}
void V8Debugger::asyncTaskFinishedForStack(void* task) {
if (!m_maxAsyncCallStackDepth) return;
// We could start instrumenting half way and the stack is empty.
- if (!m_currentStacks.size()) return;
-
+ if (!m_currentTasks.size()) return;
DCHECK(m_currentTasks.back() == task);
m_currentTasks.pop_back();
- m_currentStacks.pop_back();
+ DCHECK(m_currentAsyncParent.size() == m_currentAsyncCreation.size());
+ m_currentAsyncParent.pop_back();
+ m_currentAsyncCreation.pop_back();
+
if (m_recurringTasks.find(task) == m_recurringTasks.end()) {
asyncTaskCanceledForStack(task);
}
@@ -992,13 +1053,15 @@ void V8Debugger::asyncTaskCanceledForStepping(void* task) {
void V8Debugger::allAsyncTasksCanceled() {
m_asyncTaskStacks.clear();
m_recurringTasks.clear();
- m_currentStacks.clear();
+ m_currentAsyncParent.clear();
+ m_currentAsyncCreation.clear();
m_currentTasks.clear();
m_parentTask.clear();
m_asyncTaskCreationStacks.clear();
- m_idToTask.clear();
- m_taskToId.clear();
- m_lastTaskId = 0;
+
+ m_framesCache.clear();
+ m_allAsyncStacks.clear();
+ m_asyncStacksCount = 0;
}
void V8Debugger::muteScriptParsedEvents() {
@@ -1018,11 +1081,10 @@ std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace(
int contextGroupId = currentContextGroupId();
if (!contextGroupId) return nullptr;
- size_t stackSize =
- fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1;
- if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId))
+ int stackSize = 1;
+ if (fullStack || m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) {
stackSize = V8StackTraceImpl::maxCallStackSizeToCapture;
-
+ }
return V8StackTraceImpl::capture(this, contextGroupId, stackSize);
}
@@ -1031,4 +1093,68 @@ int V8Debugger::currentContextGroupId() {
return m_inspector->contextGroupId(m_isolate->GetCurrentContext());
}
+void V8Debugger::collectOldAsyncStacksIfNeeded() {
+ if (m_asyncStacksCount <= m_maxAsyncCallStacks) return;
+ int halfOfLimitRoundedUp =
+ m_maxAsyncCallStacks / 2 + m_maxAsyncCallStacks % 2;
+ while (m_asyncStacksCount > halfOfLimitRoundedUp) {
+ m_allAsyncStacks.pop_front();
+ --m_asyncStacksCount;
+ }
+ cleanupExpiredWeakPointers(m_asyncTaskStacks);
+ cleanupExpiredWeakPointers(m_asyncTaskCreationStacks);
+ for (auto it = m_recurringTasks.begin(); it != m_recurringTasks.end();) {
+ if (m_asyncTaskStacks.find(*it) == m_asyncTaskStacks.end()) {
+ it = m_recurringTasks.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ for (auto it = m_parentTask.begin(); it != m_parentTask.end();) {
+ if (m_asyncTaskCreationStacks.find(it->second) ==
+ m_asyncTaskCreationStacks.end() &&
+ m_asyncTaskStacks.find(it->second) == m_asyncTaskStacks.end()) {
+ it = m_parentTask.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ cleanupExpiredWeakPointers(m_framesCache);
+}
+
+std::shared_ptr<StackFrame> V8Debugger::symbolize(
+ v8::Local<v8::StackFrame> v8Frame) {
+ auto it = m_framesCache.end();
+ int frameId = 0;
+ if (m_maxAsyncCallStackDepth) {
+ frameId = v8::debug::GetStackFrameId(v8Frame);
+ it = m_framesCache.find(frameId);
+ }
+ if (it != m_framesCache.end() && it->second.lock()) return it->second.lock();
+ std::shared_ptr<StackFrame> frame(new StackFrame(v8Frame));
+ // TODO(clemensh): Figure out a way to do this translation only right before
+ // sending the stack trace over wire.
+ if (v8Frame->IsWasm()) frame->translate(&m_wasmTranslation);
+ if (m_maxAsyncCallStackDepth) {
+ m_framesCache[frameId] = frame;
+ }
+ return frame;
+}
+
+void V8Debugger::setMaxAsyncTaskStacksForTest(int limit) {
+ m_maxAsyncCallStacks = 0;
+ collectOldAsyncStacksIfNeeded();
+ m_maxAsyncCallStacks = limit;
+}
+
+void V8Debugger::dumpAsyncTaskStacksStateForTest() {
+ fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount);
+ fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size());
+ fprintf(stdout, "Created async tasks: %zu\n",
+ m_asyncTaskCreationStacks.size());
+ fprintf(stdout, "Async tasks with parent: %zu\n", m_parentTask.size());
+ fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size());
+ fprintf(stdout, "\n");
+}
+
} // namespace v8_inspector