| Index: src/inspector/v8-debugger.cc
|
| diff --git a/src/inspector/v8-debugger.cc b/src/inspector/v8-debugger.cc
|
| index f4980e2f87e1de3d4916b2c526dd7c2c0d107b3b..f67066b89ef0c03727de64384c6a7e2987055a0f 100644
|
| --- a/src/inspector/v8-debugger.cc
|
| +++ b/src/inspector/v8-debugger.cc
|
| @@ -298,6 +298,18 @@ void V8Debugger::stepIntoStatement() {
|
| continueProgram();
|
| }
|
|
|
| +Response V8Debugger::stepIntoAsync() {
|
| + DCHECK(isPaused());
|
| + DCHECK(!m_executionState.IsEmpty());
|
| + if (!m_currentCreatedAsyncTask) {
|
| + return Response::Error("No scheduled chained callback");
|
| + }
|
| + m_asyncTasksWithScheduledBreak.insert(m_currentCreatedAsyncTask);
|
| + v8::debug::ClearStepping(m_isolate);
|
| + continueProgram();
|
| + return Response::OK();
|
| +}
|
| +
|
| void V8Debugger::stepOverStatement() {
|
| DCHECK(isPaused());
|
| DCHECK(!m_executionState.IsEmpty());
|
| @@ -567,17 +579,13 @@ bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
|
| }
|
|
|
| void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
|
| - int id, int parentId) {
|
| + int id) {
|
| if (!m_maxAsyncCallStackDepth) return;
|
| // Async task events from Promises are given misaligned pointers to prevent
|
| // from overlapping with other Blink task identifiers. There is a single
|
| // namespace of such ids, managed by src/js/promise.js.
|
| void* ptr = reinterpret_cast<void*>(id * 2 + 1);
|
| switch (type) {
|
| - case v8::debug::kDebugPromiseCreated:
|
| - asyncTaskCreated(
|
| - ptr, parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr);
|
| - break;
|
| case v8::debug::kDebugEnqueueAsyncFunction:
|
| asyncTaskScheduled("async function", ptr, true);
|
| break;
|
| @@ -599,6 +607,32 @@ void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type,
|
| }
|
| }
|
|
|
| +void V8Debugger::PromiseCreatedEvent(int id, int parentId, bool isBreakable) {
|
| + if (!m_maxAsyncCallStackDepth) return;
|
| + void* task = reinterpret_cast<void*>(id * 2 + 1);
|
| + void* parentTask =
|
| + parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr;
|
| + if (parentTask) m_parentTask[task] = parentTask;
|
| + v8::HandleScope scope(m_isolate);
|
| + // We don't need to pass context group id here because we gets 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);
|
| + }
|
| + if (!parentTask || !isBreakable) return;
|
| + V8DebuggerAgentImpl* agent =
|
| + m_inspector->enabledDebuggerAgentForGroup(currentContextGroupId());
|
| + if (!agent) return;
|
| + m_currentCreatedAsyncTask = task;
|
| + agent->asyncTaskCreated();
|
| + m_currentCreatedAsyncTask = nullptr;
|
| +}
|
| +
|
| V8StackTraceImpl* V8Debugger::currentAsyncCallChain() {
|
| if (!m_currentStacks.size()) return nullptr;
|
| return m_currentStacks.back().get();
|
| @@ -837,11 +871,7 @@ bool V8Debugger::isPaused() { return !m_pausedContext.IsEmpty(); }
|
|
|
| std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace(
|
| v8::Local<v8::StackTrace> stackTrace) {
|
| - int contextGroupId =
|
| - m_isolate->InContext()
|
| - ? m_inspector->contextGroupId(m_isolate->GetCurrentContext())
|
| - : 0;
|
| - return V8StackTraceImpl::create(this, contextGroupId, stackTrace,
|
| + return V8StackTraceImpl::create(this, currentContextGroupId(), stackTrace,
|
| V8StackTraceImpl::maxCallStackSizeToCapture);
|
| }
|
|
|
| @@ -874,22 +904,6 @@ void V8Debugger::registerAsyncTaskIfNeeded(void* task) {
|
| }
|
| }
|
|
|
| -void V8Debugger::asyncTaskCreated(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 gets 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);
|
| - }
|
| -}
|
| -
|
| void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task,
|
| bool recurring) {
|
| if (!m_maxAsyncCallStackDepth) return;
|
| @@ -900,13 +914,9 @@ void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task,
|
| bool recurring) {
|
| if (!m_maxAsyncCallStackDepth) return;
|
| v8::HandleScope scope(m_isolate);
|
| - int contextGroupId =
|
| - m_isolate->InContext()
|
| - ? m_inspector->contextGroupId(m_isolate->GetCurrentContext())
|
| - : 0;
|
| std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture(
|
| - this, contextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture,
|
| - taskName);
|
| + this, currentContextGroupId(),
|
| + V8StackTraceImpl::maxCallStackSizeToCapture, taskName);
|
| if (chain) {
|
| m_asyncTaskStacks[task] = std::move(chain);
|
| if (recurring) m_recurringTasks.insert(task);
|
| @@ -920,6 +930,8 @@ void V8Debugger::asyncTaskCanceled(void* task) {
|
| m_recurringTasks.erase(task);
|
| m_parentTask.erase(task);
|
| m_asyncTaskCreationStacks.erase(task);
|
| + if (m_currentCreatedAsyncTask == task) m_currentCreatedAsyncTask = nullptr;
|
| + m_asyncTasksWithScheduledBreak.erase(task);
|
| auto it = m_taskToId.find(task);
|
| if (it == m_taskToId.end()) return;
|
| m_idToTask.erase(it->second);
|
| @@ -947,6 +959,13 @@ void V8Debugger::asyncTaskStarted(void* task) {
|
| stack->setCreation(itCreation->second->cloneImpl());
|
| }
|
| m_currentStacks.push_back(std::move(stack));
|
| + if (m_asyncTasksWithScheduledBreak.find(task) ==
|
| + m_asyncTasksWithScheduledBreak.end())
|
| + return;
|
| + V8DebuggerAgentImpl* agent =
|
| + m_inspector->enabledDebuggerAgentForGroup(currentContextGroupId());
|
| + if (!agent) return;
|
| + agent->asyncTaskStarted();
|
| }
|
|
|
| void V8Debugger::asyncTaskFinished(void* task) {
|
| @@ -958,6 +977,15 @@ void V8Debugger::asyncTaskFinished(void* task) {
|
| m_currentTasks.pop_back();
|
|
|
| m_currentStacks.pop_back();
|
| + if (m_asyncTasksWithScheduledBreak.find(task) !=
|
| + m_asyncTasksWithScheduledBreak.end()) {
|
| + V8DebuggerAgentImpl* agent =
|
| + m_inspector->enabledDebuggerAgentForGroup(currentContextGroupId());
|
| + if (!agent) return;
|
| + agent->asyncTaskFinished();
|
| + m_asyncTasksWithScheduledBreak.erase(task);
|
| + }
|
| +
|
| if (m_recurringTasks.find(task) == m_recurringTasks.end()) {
|
| asyncTaskCanceled(task);
|
| }
|
| @@ -970,6 +998,8 @@ void V8Debugger::allAsyncTasksCanceled() {
|
| m_currentTasks.clear();
|
| m_parentTask.clear();
|
| m_asyncTaskCreationStacks.clear();
|
| + m_currentCreatedAsyncTask = nullptr;
|
| + m_asyncTasksWithScheduledBreak.clear();
|
| m_idToTask.clear();
|
| m_taskToId.clear();
|
| m_lastTaskId = 0;
|
| @@ -986,13 +1016,10 @@ void V8Debugger::unmuteScriptParsedEvents() {
|
|
|
| std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace(
|
| bool fullStack) {
|
| - if (!m_isolate->InContext()) return nullptr;
|
| -
|
| - v8::HandleScope handles(m_isolate);
|
| - int contextGroupId =
|
| - m_inspector->contextGroupId(m_isolate->GetCurrentContext());
|
| + int contextGroupId = currentContextGroupId();
|
| if (!contextGroupId) return nullptr;
|
|
|
| + v8::HandleScope handles(m_isolate);
|
| size_t stackSize =
|
| fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1;
|
| if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId))
|
| @@ -1001,4 +1028,9 @@ std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace(
|
| return V8StackTraceImpl::capture(this, contextGroupId, stackSize);
|
| }
|
|
|
| +int V8Debugger::currentContextGroupId() {
|
| + if (!m_isolate->InContext()) return 0;
|
| + return m_inspector->contextGroupId(m_isolate->GetCurrentContext());
|
| +}
|
| +
|
| } // namespace v8_inspector
|
|
|