Commit 760c56bd authored by kozyatinskiy's avatar kozyatinskiy Committed by Commit bot

[inspector] changed a way of preserving stepping between tasks

Indisputable profit:
- correct break location in next task (see tests),
- stepOver with async await never lands in random code (see related test and issue),
- inspector doesn't store current stepping state in debugger agent and completely trust V8 - step to new inspector-V8 design (I will finish design doc soon).
- willExecuteScript and didExecuteScript instrumentation could be removed from code base - reduce probability of future errors.
- finally - less code,
- stepping implementation in V8 makes another step to follow our stepping strategy (stepOut should do stepInto and break when exit current frame) (another one one page design doc based on @aandrey comment is coming),
- knowledge about existing of context groups is still inspector-only.

Disputable part is related to super rare scenario when in single isolate we have more then one context group id with enabled debugger agent:
- if one agent request break in own context (stepping, pause, e.t.c.) then we ignore all breaks in another agent. From one hand it looks like good: user clicks stepInto and they don't expect that execution could be paused by another instance of DevTools in unobservable from current DevTools way (second DevTools will get paused notification and run nested message loop). From another hand we shouldn't ignore breakpoints or debugger statement never. In general, I think that proposed behavior is rathe feature then issue.
- and disadvantage, on attempt to break in non-target context group id we just call StepOut until reach target context group id, step out call could deoptimize code in non related to current debugger agent context. But break could happens only in case of debugger stmt or breakpoint - sound like minor issue. Ignoring break on exception sounds like real issue but by module of rareness of this case I think we can ignore this.

Implementation details:
- when debugger agent request break for any reason it passes target context group id to V8Debugger - last agent requesting break is preferred.
- when V8Debugger gets BreakProgramRequested notification from V8, it checks current context group id against target context group id, if they match then just process break as usual otherwise makes StepOut action,
- debug.cc at the end of microtask if last_scheduled_action is StepOut, schedules StepIn and will break on first instruction in next task.

BUG=chromium:654022
R=dgozman@chromium.org,yangguo@chromium.org

Review-Url: https://codereview.chromium.org/2748503002
Cr-Commit-Position: refs/heads/master@{#44034}
parent 12d815b3
...@@ -740,9 +740,11 @@ v8::Local<v8::Object> V8Console::createConsole( ...@@ -740,9 +740,11 @@ v8::Local<v8::Object> V8Console::createConsole(
if (inspector->compileAndRunInternalScript(context, assertSource) if (inspector->compileAndRunInternalScript(context, assertSource)
.ToLocal(&setupFunction) && .ToLocal(&setupFunction) &&
setupFunction->IsFunction()) { setupFunction->IsFunction()) {
inspector->callInternalFunction( v8::MicrotasksScope microtasksScope(
v8::Local<v8::Function>::Cast(setupFunction), context, console, 0, isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
nullptr); v8::MaybeLocal<v8::Value> result;
result = v8::Local<v8::Function>::Cast(setupFunction)
->Call(context, console, 0, nullptr);
} }
if (hasMemoryAttribute) if (hasMemoryAttribute)
......
...@@ -198,10 +198,7 @@ V8DebuggerAgentImpl::V8DebuggerAgentImpl( ...@@ -198,10 +198,7 @@ V8DebuggerAgentImpl::V8DebuggerAgentImpl(
m_state(state), m_state(state),
m_frontend(frontendChannel), m_frontend(frontendChannel),
m_isolate(m_inspector->isolate()), m_isolate(m_inspector->isolate()),
m_scheduledDebuggerStep(NoStep), m_javaScriptPauseScheduled(false) {}
m_javaScriptPauseScheduled(false),
m_recursionLevelForStepOut(0) {
}
V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {} V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {}
...@@ -253,7 +250,6 @@ Response V8DebuggerAgentImpl::disable() { ...@@ -253,7 +250,6 @@ Response V8DebuggerAgentImpl::disable() {
m_debugger->setAsyncCallStackDepth(this, 0); m_debugger->setAsyncCallStackDepth(this, 0);
m_continueToLocationBreakpointId = String16(); m_continueToLocationBreakpointId = String16();
clearBreakDetails(); clearBreakDetails();
m_scheduledDebuggerStep = NoStep;
m_javaScriptPauseScheduled = false; m_javaScriptPauseScheduled = false;
m_skipAllPauses = false; m_skipAllPauses = false;
m_state->setBoolean(DebuggerAgentState::skipAllPauses, false); m_state->setBoolean(DebuggerAgentState::skipAllPauses, false);
...@@ -688,26 +684,20 @@ void V8DebuggerAgentImpl::clearBreakDetails() { ...@@ -688,26 +684,20 @@ void V8DebuggerAgentImpl::clearBreakDetails() {
void V8DebuggerAgentImpl::schedulePauseOnNextStatement( void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
const String16& breakReason, const String16& breakReason,
std::unique_ptr<protocol::DictionaryValue> data) { std::unique_ptr<protocol::DictionaryValue> data) {
if (!enabled() || m_scheduledDebuggerStep == StepInto || if (!enabled() || m_javaScriptPauseScheduled || isPaused() ||
m_javaScriptPauseScheduled || isPaused() ||
!m_debugger->breakpointsActivated()) !m_debugger->breakpointsActivated())
return; return;
if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(true); if (m_breakReason.empty()) {
m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId());
}
pushBreakDetails(breakReason, std::move(data)); pushBreakDetails(breakReason, std::move(data));
} }
void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() {
DCHECK(enabled());
if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled ||
isPaused())
return;
m_debugger->setPauseOnNextStatement(true);
}
void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
if (m_javaScriptPauseScheduled || isPaused()) return; if (m_javaScriptPauseScheduled || isPaused()) return;
popBreakDetails(); popBreakDetails();
if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(false); if (m_breakReason.empty())
m_debugger->setPauseOnNextStatement(false, m_session->contextGroupId());
} }
Response V8DebuggerAgentImpl::pause() { Response V8DebuggerAgentImpl::pause() {
...@@ -715,14 +705,12 @@ Response V8DebuggerAgentImpl::pause() { ...@@ -715,14 +705,12 @@ Response V8DebuggerAgentImpl::pause() {
if (m_javaScriptPauseScheduled || isPaused()) return Response::OK(); if (m_javaScriptPauseScheduled || isPaused()) return Response::OK();
clearBreakDetails(); clearBreakDetails();
m_javaScriptPauseScheduled = true; m_javaScriptPauseScheduled = true;
m_scheduledDebuggerStep = NoStep; m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId());
m_debugger->setPauseOnNextStatement(true);
return Response::OK(); return Response::OK();
} }
Response V8DebuggerAgentImpl::resume() { Response V8DebuggerAgentImpl::resume() {
if (!isPaused()) return Response::Error(kDebuggerNotPaused); if (!isPaused()) return Response::Error(kDebuggerNotPaused);
m_scheduledDebuggerStep = NoStep;
m_session->releaseObjectGroup(kBacktraceObjectGroup); m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->continueProgram(); m_debugger->continueProgram();
return Response::OK(); return Response::OK();
...@@ -730,30 +718,22 @@ Response V8DebuggerAgentImpl::resume() { ...@@ -730,30 +718,22 @@ Response V8DebuggerAgentImpl::resume() {
Response V8DebuggerAgentImpl::stepOver() { Response V8DebuggerAgentImpl::stepOver() {
if (!isPaused()) return Response::Error(kDebuggerNotPaused); if (!isPaused()) return Response::Error(kDebuggerNotPaused);
// StepOver at function return point should fallback to StepInto.
JavaScriptCallFrame* frame =
!m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr;
if (frame && frame->isAtReturn()) return stepInto();
m_scheduledDebuggerStep = StepOver;
m_session->releaseObjectGroup(kBacktraceObjectGroup); m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->stepOverStatement(); m_debugger->stepOverStatement(m_session->contextGroupId());
return Response::OK(); return Response::OK();
} }
Response V8DebuggerAgentImpl::stepInto() { Response V8DebuggerAgentImpl::stepInto() {
if (!isPaused()) return Response::Error(kDebuggerNotPaused); if (!isPaused()) return Response::Error(kDebuggerNotPaused);
m_scheduledDebuggerStep = StepInto;
m_session->releaseObjectGroup(kBacktraceObjectGroup); m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->stepIntoStatement(); m_debugger->stepIntoStatement(m_session->contextGroupId());
return Response::OK(); return Response::OK();
} }
Response V8DebuggerAgentImpl::stepOut() { Response V8DebuggerAgentImpl::stepOut() {
if (!isPaused()) return Response::Error(kDebuggerNotPaused); if (!isPaused()) return Response::Error(kDebuggerNotPaused);
m_scheduledDebuggerStep = StepOut;
m_recursionLevelForStepOut = 1;
m_session->releaseObjectGroup(kBacktraceObjectGroup); m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->stepOutOfFunction(); m_debugger->stepOutOfFunction(m_session->contextGroupId());
return Response::OK(); return Response::OK();
} }
...@@ -774,8 +754,6 @@ bool V8DebuggerAgentImpl::shouldBreakInScheduledAsyncTask() { ...@@ -774,8 +754,6 @@ bool V8DebuggerAgentImpl::shouldBreakInScheduledAsyncTask() {
if (!m_stepIntoAsyncCallback) return false; if (!m_stepIntoAsyncCallback) return false;
m_stepIntoAsyncCallback->sendSuccess(); m_stepIntoAsyncCallback->sendSuccess();
m_stepIntoAsyncCallback.reset(); m_stepIntoAsyncCallback.reset();
m_scheduledDebuggerStep = NoStep;
v8::debug::ClearStepping(m_isolate);
return true; return true;
} }
...@@ -947,33 +925,6 @@ Response V8DebuggerAgentImpl::setBlackboxedRanges( ...@@ -947,33 +925,6 @@ Response V8DebuggerAgentImpl::setBlackboxedRanges(
return Response::OK(); return Response::OK();
} }
void V8DebuggerAgentImpl::willExecuteScript(int scriptId) {
changeJavaScriptRecursionLevel(+1);
if (m_scheduledDebuggerStep != StepInto) return;
schedulePauseOnNextStatementIfSteppingInto();
}
void V8DebuggerAgentImpl::didExecuteScript() {
changeJavaScriptRecursionLevel(-1);
}
void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) {
if (m_javaScriptPauseScheduled && !m_skipAllPauses && !isPaused()) {
// Do not ever loose user's pause request until we have actually paused.
m_debugger->setPauseOnNextStatement(true);
}
if (m_scheduledDebuggerStep == StepOut) {
m_recursionLevelForStepOut += step;
if (!m_recursionLevelForStepOut) {
// When StepOut crosses a task boundary (i.e. js -> c++) from where it was
// requested,
// switch stepping to step into a next JS task, as if we exited to a
// blackboxed framework.
m_scheduledDebuggerStep = StepInto;
}
}
}
Response V8DebuggerAgentImpl::currentCallFrames( Response V8DebuggerAgentImpl::currentCallFrames(
std::unique_ptr<Array<CallFrame>>* result) { std::unique_ptr<Array<CallFrame>>* result) {
if (!isPaused()) { if (!isPaused()) {
...@@ -1287,7 +1238,6 @@ void V8DebuggerAgentImpl::didPause(int contextId, ...@@ -1287,7 +1238,6 @@ void V8DebuggerAgentImpl::didPause(int contextId,
m_frontend.paused(std::move(protocolCallFrames), breakReason, m_frontend.paused(std::move(protocolCallFrames), breakReason,
std::move(breakAuxData), std::move(hitBreakpointIds), std::move(breakAuxData), std::move(hitBreakpointIds),
currentAsyncStackTrace()); currentAsyncStackTrace());
m_scheduledDebuggerStep = NoStep;
m_javaScriptPauseScheduled = false; m_javaScriptPauseScheduled = false;
if (!m_continueToLocationBreakpointId.isEmpty()) { if (!m_continueToLocationBreakpointId.isEmpty()) {
...@@ -1310,12 +1260,11 @@ void V8DebuggerAgentImpl::breakProgram( ...@@ -1310,12 +1260,11 @@ void V8DebuggerAgentImpl::breakProgram(
std::vector<BreakReason> currentScheduledReason; std::vector<BreakReason> currentScheduledReason;
currentScheduledReason.swap(m_breakReason); currentScheduledReason.swap(m_breakReason);
pushBreakDetails(breakReason, std::move(data)); pushBreakDetails(breakReason, std::move(data));
m_scheduledDebuggerStep = NoStep;
m_debugger->breakProgram(); m_debugger->breakProgram();
popBreakDetails(); popBreakDetails();
m_breakReason.swap(currentScheduledReason); m_breakReason.swap(currentScheduledReason);
if (!m_breakReason.empty()) { if (!m_breakReason.empty()) {
m_debugger->setPauseOnNextStatement(true); m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId());
} }
} }
...@@ -1347,7 +1296,6 @@ void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, ...@@ -1347,7 +1296,6 @@ void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId,
void V8DebuggerAgentImpl::reset() { void V8DebuggerAgentImpl::reset() {
if (!enabled()) return; if (!enabled()) return;
m_scheduledDebuggerStep = NoStep;
m_blackboxedPositions.clear(); m_blackboxedPositions.clear();
resetBlackboxedStateCache(); resetBlackboxedStateCache();
m_scripts.clear(); m_scripts.clear();
......
...@@ -134,8 +134,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { ...@@ -134,8 +134,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
bool isPromiseRejection, bool isUncaught, bool isOOMBreak); bool isPromiseRejection, bool isUncaught, bool isOOMBreak);
void didContinue(); void didContinue();
void didParseSource(std::unique_ptr<V8DebuggerScript>, bool success); void didParseSource(std::unique_ptr<V8DebuggerScript>, bool success);
void willExecuteScript(int scriptId);
void didExecuteScript();
bool isFunctionBlackboxed(const String16& scriptId, bool isFunctionBlackboxed(const String16& scriptId,
const v8::debug::Location& start, const v8::debug::Location& start,
...@@ -150,14 +148,10 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { ...@@ -150,14 +148,10 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
private: private:
void enableImpl(); void enableImpl();
void schedulePauseOnNextStatementIfSteppingInto();
Response currentCallFrames( Response currentCallFrames(
std::unique_ptr<protocol::Array<protocol::Debugger::CallFrame>>*); std::unique_ptr<protocol::Array<protocol::Debugger::CallFrame>>*);
std::unique_ptr<protocol::Runtime::StackTrace> currentAsyncStackTrace(); std::unique_ptr<protocol::Runtime::StackTrace> currentAsyncStackTrace();
void changeJavaScriptRecursionLevel(int step);
void setPauseOnExceptionsImpl(int); void setPauseOnExceptionsImpl(int);
std::unique_ptr<protocol::Debugger::Location> resolveBreakpoint( std::unique_ptr<protocol::Debugger::Location> resolveBreakpoint(
...@@ -182,8 +176,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { ...@@ -182,8 +176,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
protocol::HashMap<String16, std::pair<String16, BreakpointSource>>; protocol::HashMap<String16, std::pair<String16, BreakpointSource>>;
using MuteBreakpoins = protocol::HashMap<String16, std::pair<String16, int>>; using MuteBreakpoins = protocol::HashMap<String16, std::pair<String16, int>>;
enum DebuggerStep { NoStep = 0, StepInto, StepOver, StepOut };
V8InspectorImpl* m_inspector; V8InspectorImpl* m_inspector;
V8Debugger* m_debugger; V8Debugger* m_debugger;
V8InspectorSessionImpl* m_session; V8InspectorSessionImpl* m_session;
...@@ -206,10 +198,7 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { ...@@ -206,10 +198,7 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
std::unique_ptr<protocol::DictionaryValue> breakAuxData); std::unique_ptr<protocol::DictionaryValue> breakAuxData);
void popBreakDetails(); void popBreakDetails();
DebuggerStep m_scheduledDebuggerStep;
bool m_javaScriptPauseScheduled; bool m_javaScriptPauseScheduled;
int m_recursionLevelForStepOut;
bool m_skipAllPauses = false; bool m_skipAllPauses = false;
std::unique_ptr<V8Regex> m_blackboxPattern; std::unique_ptr<V8Regex> m_blackboxPattern;
......
...@@ -328,8 +328,14 @@ void V8Debugger::setPauseOnExceptionsState( ...@@ -328,8 +328,14 @@ void V8Debugger::setPauseOnExceptionsState(
m_pauseOnExceptionsState = pauseOnExceptionsState; m_pauseOnExceptionsState = pauseOnExceptionsState;
} }
void V8Debugger::setPauseOnNextStatement(bool pause) { void V8Debugger::setPauseOnNextStatement(bool pause, int targetContextGroupId) {
if (isPaused()) return; if (isPaused()) return;
DCHECK(targetContextGroupId);
if (!pause && m_targetContextGroupId &&
m_targetContextGroupId != targetContextGroupId) {
return;
}
m_targetContextGroupId = targetContextGroupId;
if (pause) if (pause)
v8::debug::DebugBreak(m_isolate); v8::debug::DebugBreak(m_isolate);
else else
...@@ -354,23 +360,29 @@ void V8Debugger::continueProgram() { ...@@ -354,23 +360,29 @@ void V8Debugger::continueProgram() {
m_executionState.Clear(); m_executionState.Clear();
} }
void V8Debugger::stepIntoStatement() { void V8Debugger::stepIntoStatement(int targetContextGroupId) {
DCHECK(isPaused()); DCHECK(isPaused());
DCHECK(!m_executionState.IsEmpty()); DCHECK(!m_executionState.IsEmpty());
DCHECK(targetContextGroupId);
m_targetContextGroupId = targetContextGroupId;
v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); v8::debug::PrepareStep(m_isolate, v8::debug::StepIn);
continueProgram(); continueProgram();
} }
void V8Debugger::stepOverStatement() { void V8Debugger::stepOverStatement(int targetContextGroupId) {
DCHECK(isPaused()); DCHECK(isPaused());
DCHECK(!m_executionState.IsEmpty()); DCHECK(!m_executionState.IsEmpty());
DCHECK(targetContextGroupId);
m_targetContextGroupId = targetContextGroupId;
v8::debug::PrepareStep(m_isolate, v8::debug::StepNext); v8::debug::PrepareStep(m_isolate, v8::debug::StepNext);
continueProgram(); continueProgram();
} }
void V8Debugger::stepOutOfFunction() { void V8Debugger::stepOutOfFunction(int targetContextGroupId) {
DCHECK(isPaused()); DCHECK(isPaused());
DCHECK(!m_executionState.IsEmpty()); DCHECK(!m_executionState.IsEmpty());
DCHECK(targetContextGroupId);
m_targetContextGroupId = targetContextGroupId;
v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); v8::debug::PrepareStep(m_isolate, v8::debug::StepOut);
continueProgram(); continueProgram();
} }
...@@ -504,6 +516,12 @@ void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext, ...@@ -504,6 +516,12 @@ void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext,
// Don't allow nested breaks. // Don't allow nested breaks.
if (isPaused()) return; if (isPaused()) return;
int contextGroupId = m_inspector->contextGroupId(pausedContext);
if (m_targetContextGroupId && contextGroupId != m_targetContextGroupId) {
v8::debug::PrepareStep(m_isolate, v8::debug::StepOut);
return;
}
m_targetContextGroupId = 0;
V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup(
m_inspector->contextGroupId(pausedContext)); m_inspector->contextGroupId(pausedContext));
if (!agent || (agent->skipAllPauses() && !m_scheduledOOMBreak)) return; if (!agent || (agent->skipAllPauses() && !m_scheduledOOMBreak)) return;
...@@ -549,7 +567,10 @@ void V8Debugger::v8OOMCallback(void* data) { ...@@ -549,7 +567,10 @@ void V8Debugger::v8OOMCallback(void* data) {
V8Debugger* thisPtr = static_cast<V8Debugger*>(data); V8Debugger* thisPtr = static_cast<V8Debugger*>(data);
thisPtr->m_isolate->IncreaseHeapLimitForDebugging(); thisPtr->m_isolate->IncreaseHeapLimitForDebugging();
thisPtr->m_scheduledOOMBreak = true; thisPtr->m_scheduledOOMBreak = true;
thisPtr->setPauseOnNextStatement(true); v8::Local<v8::Context> context = thisPtr->m_isolate->GetEnteredContext();
DCHECK(!context.IsEmpty());
thisPtr->setPauseOnNextStatement(
true, thisPtr->m_inspector->contextGroupId(context));
} }
void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script, void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script,
...@@ -660,6 +681,7 @@ void V8Debugger::handleAsyncTaskStepping(v8::Local<v8::Context> context, ...@@ -660,6 +681,7 @@ void V8Debugger::handleAsyncTaskStepping(v8::Local<v8::Context> context,
if (createdByUser && type == v8::debug::kDebugPromiseCreated) { if (createdByUser && type == v8::debug::kDebugPromiseCreated) {
if (agent->shouldBreakInScheduledAsyncTask()) { if (agent->shouldBreakInScheduledAsyncTask()) {
m_taskWithScheduledBreak = task; m_taskWithScheduledBreak = task;
v8::debug::ClearStepping(m_isolate);
} }
return; return;
} }
......
...@@ -41,13 +41,14 @@ class V8Debugger : public v8::debug::DebugDelegate { ...@@ -41,13 +41,14 @@ class V8Debugger : public v8::debug::DebugDelegate {
v8::debug::ExceptionBreakState getPauseOnExceptionsState(); v8::debug::ExceptionBreakState getPauseOnExceptionsState();
void setPauseOnExceptionsState(v8::debug::ExceptionBreakState); void setPauseOnExceptionsState(v8::debug::ExceptionBreakState);
void setPauseOnNextStatement(bool);
bool canBreakProgram(); bool canBreakProgram();
void breakProgram(); void breakProgram();
void continueProgram(); void continueProgram();
void stepIntoStatement();
void stepOverStatement(); void setPauseOnNextStatement(bool, int targetContextGroupId);
void stepOutOfFunction(); void stepIntoStatement(int targetContextGroupId);
void stepOverStatement(int targetContextGroupId);
void stepOutOfFunction(int targetContextGroupId);
Response setScriptSource( Response setScriptSource(
const String16& sourceID, v8::Local<v8::String> newSource, bool dryRun, const String16& sourceID, v8::Local<v8::String> newSource, bool dryRun,
...@@ -162,6 +163,7 @@ class V8Debugger : public v8::debug::DebugDelegate { ...@@ -162,6 +163,7 @@ class V8Debugger : public v8::debug::DebugDelegate {
bool m_runningNestedMessageLoop; bool m_runningNestedMessageLoop;
int m_ignoreScriptParsedEventsCounter; int m_ignoreScriptParsedEventsCounter;
bool m_scheduledOOMBreak = false; bool m_scheduledOOMBreak = false;
int m_targetContextGroupId = 0;
using AsyncTaskToStackTrace = using AsyncTaskToStackTrace =
protocol::HashMap<void*, std::unique_ptr<V8StackTraceImpl>>; protocol::HashMap<void*, std::unique_ptr<V8StackTraceImpl>>;
......
...@@ -90,52 +90,6 @@ V8ProfilerAgentImpl* V8InspectorImpl::enabledProfilerAgentForGroup( ...@@ -90,52 +90,6 @@ V8ProfilerAgentImpl* V8InspectorImpl::enabledProfilerAgentForGroup(
return agent && agent->enabled() ? agent : nullptr; return agent && agent->enabled() ? agent : nullptr;
} }
v8::MaybeLocal<v8::Value> V8InspectorImpl::runCompiledScript(
v8::Local<v8::Context> context, v8::Local<v8::Script> script) {
v8::MicrotasksScope microtasksScope(m_isolate,
v8::MicrotasksScope::kRunMicrotasks);
int groupId = contextGroupId(context);
if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId))
agent->willExecuteScript(script->GetUnboundScript()->GetId());
v8::MaybeLocal<v8::Value> result = script->Run(context);
// Get agent from the map again, since it could have detached during script
// execution.
if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId))
agent->didExecuteScript();
return result;
}
v8::MaybeLocal<v8::Value> V8InspectorImpl::callFunction(
v8::Local<v8::Function> function, v8::Local<v8::Context> context,
v8::Local<v8::Value> receiver, int argc, v8::Local<v8::Value> info[]) {
return callFunction(function, context, receiver, argc, info,
v8::MicrotasksScope::kRunMicrotasks);
}
v8::MaybeLocal<v8::Value> V8InspectorImpl::callInternalFunction(
v8::Local<v8::Function> function, v8::Local<v8::Context> context,
v8::Local<v8::Value> receiver, int argc, v8::Local<v8::Value> info[]) {
return callFunction(function, context, receiver, argc, info,
v8::MicrotasksScope::kDoNotRunMicrotasks);
}
v8::MaybeLocal<v8::Value> V8InspectorImpl::callFunction(
v8::Local<v8::Function> function, v8::Local<v8::Context> context,
v8::Local<v8::Value> receiver, int argc, v8::Local<v8::Value> info[],
v8::MicrotasksScope::Type runMicrotasks) {
v8::MicrotasksScope microtasksScope(m_isolate, runMicrotasks);
int groupId = contextGroupId(context);
if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId))
agent->willExecuteScript(function->ScriptId());
v8::MaybeLocal<v8::Value> result =
function->Call(context, receiver, argc, info);
// Get agent from the map again, since it could have detached during script
// execution.
if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId))
agent->didExecuteScript();
return result;
}
v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript( v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript(
v8::Local<v8::Context> context, v8::Local<v8::String> source) { v8::Local<v8::Context> context, v8::Local<v8::String> source) {
v8::Local<v8::UnboundScript> unboundScript; v8::Local<v8::UnboundScript> unboundScript;
...@@ -287,17 +241,9 @@ void V8InspectorImpl::resetContextGroup(int contextGroupId) { ...@@ -287,17 +241,9 @@ void V8InspectorImpl::resetContextGroup(int contextGroupId) {
void V8InspectorImpl::willExecuteScript(v8::Local<v8::Context> context, void V8InspectorImpl::willExecuteScript(v8::Local<v8::Context> context,
int scriptId) { int scriptId) {
if (V8DebuggerAgentImpl* agent =
enabledDebuggerAgentForGroup(contextGroupId(context))) {
agent->willExecuteScript(scriptId);
}
} }
void V8InspectorImpl::didExecuteScript(v8::Local<v8::Context> context) { void V8InspectorImpl::didExecuteScript(v8::Local<v8::Context> context) {
if (V8DebuggerAgentImpl* agent =
enabledDebuggerAgentForGroup(contextGroupId(context))) {
agent->didExecuteScript();
}
} }
void V8InspectorImpl::idleStarted() { void V8InspectorImpl::idleStarted() {
......
...@@ -60,19 +60,8 @@ class V8InspectorImpl : public V8Inspector { ...@@ -60,19 +60,8 @@ class V8InspectorImpl : public V8Inspector {
int contextGroupId(v8::Local<v8::Context>); int contextGroupId(v8::Local<v8::Context>);
int contextGroupId(int contextId); int contextGroupId(int contextId);
v8::MaybeLocal<v8::Value> runCompiledScript(v8::Local<v8::Context>,
v8::Local<v8::Script>);
v8::MaybeLocal<v8::Value> callFunction(v8::Local<v8::Function>,
v8::Local<v8::Context>,
v8::Local<v8::Value> receiver,
int argc, v8::Local<v8::Value> info[]);
v8::MaybeLocal<v8::Value> compileAndRunInternalScript(v8::Local<v8::Context>, v8::MaybeLocal<v8::Value> compileAndRunInternalScript(v8::Local<v8::Context>,
v8::Local<v8::String>); v8::Local<v8::String>);
v8::MaybeLocal<v8::Value> callInternalFunction(v8::Local<v8::Function>,
v8::Local<v8::Context>,
v8::Local<v8::Value> receiver,
int argc,
v8::Local<v8::Value> info[]);
v8::MaybeLocal<v8::Script> compileScript(v8::Local<v8::Context>, v8::MaybeLocal<v8::Script> compileScript(v8::Local<v8::Context>,
const String16& code, const String16& code,
const String16& fileName); const String16& fileName);
...@@ -126,11 +115,6 @@ class V8InspectorImpl : public V8Inspector { ...@@ -126,11 +115,6 @@ class V8InspectorImpl : public V8Inspector {
V8ProfilerAgentImpl* enabledProfilerAgentForGroup(int contextGroupId); V8ProfilerAgentImpl* enabledProfilerAgentForGroup(int contextGroupId);
private: private:
v8::MaybeLocal<v8::Value> callFunction(
v8::Local<v8::Function>, v8::Local<v8::Context>,
v8::Local<v8::Value> receiver, int argc, v8::Local<v8::Value> info[],
v8::MicrotasksScope::Type runMicrotasks);
v8::Isolate* m_isolate; v8::Isolate* m_isolate;
V8InspectorClient* m_client; V8InspectorClient* m_client;
std::unique_ptr<V8Debugger> m_debugger; std::unique_ptr<V8Debugger> m_debugger;
......
...@@ -297,7 +297,9 @@ void V8RuntimeAgentImpl::evaluate( ...@@ -297,7 +297,9 @@ void V8RuntimeAgentImpl::evaluate(
v8::Local<v8::Script> script; v8::Local<v8::Script> script;
if (m_inspector->compileScript(scope.context(), expression, String16()) if (m_inspector->compileScript(scope.context(), expression, String16())
.ToLocal(&script)) { .ToLocal(&script)) {
maybeResultValue = m_inspector->runCompiledScript(scope.context(), script); v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
v8::MicrotasksScope::kRunMicrotasks);
maybeResultValue = script->Run(scope.context());
} }
if (evalIsDisabled) scope.context()->AllowCodeGenerationFromStrings(false); if (evalIsDisabled) scope.context()->AllowCodeGenerationFromStrings(false);
...@@ -385,8 +387,9 @@ void V8RuntimeAgentImpl::callFunctionOn( ...@@ -385,8 +387,9 @@ void V8RuntimeAgentImpl::callFunctionOn(
if (m_inspector if (m_inspector
->compileScript(scope.context(), "(" + expression + ")", String16()) ->compileScript(scope.context(), "(" + expression + ")", String16())
.ToLocal(&functionScript)) { .ToLocal(&functionScript)) {
maybeFunctionValue = v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
m_inspector->runCompiledScript(scope.context(), functionScript); v8::MicrotasksScope::kRunMicrotasks);
maybeFunctionValue = functionScript->Run(scope.context());
} }
// Re-initialize after running client's code, as it could have destroyed // Re-initialize after running client's code, as it could have destroyed
// context or session. // context or session.
...@@ -411,9 +414,13 @@ void V8RuntimeAgentImpl::callFunctionOn( ...@@ -411,9 +414,13 @@ void V8RuntimeAgentImpl::callFunctionOn(
return; return;
} }
v8::MaybeLocal<v8::Value> maybeResultValue = m_inspector->callFunction( v8::MaybeLocal<v8::Value> maybeResultValue;
functionValue.As<v8::Function>(), scope.context(), scope.object(), argc, {
argv.get()); v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
v8::MicrotasksScope::kRunMicrotasks);
maybeResultValue = functionValue.As<v8::Function>()->Call(
scope.context(), scope.object(), argc, argv.get());
}
// Re-initialize after running client's code, as it could have destroyed // Re-initialize after running client's code, as it could have destroyed
// context or session. // context or session.
response = scope.initialize(); response = scope.initialize();
...@@ -620,8 +627,12 @@ void V8RuntimeAgentImpl::runScript( ...@@ -620,8 +627,12 @@ void V8RuntimeAgentImpl::runScript(
if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI(); if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
v8::MaybeLocal<v8::Value> maybeResultValue = v8::MaybeLocal<v8::Value> maybeResultValue;
m_inspector->runCompiledScript(scope.context(), script); {
v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
v8::MicrotasksScope::kRunMicrotasks);
maybeResultValue = script->Run(scope.context());
}
// Re-initialize after running client's code, as it could have destroyed // Re-initialize after running client's code, as it could have destroyed
// context or session. // context or session.
......
...@@ -3317,8 +3317,6 @@ void Isolate::FireCallCompletedCallback() { ...@@ -3317,8 +3317,6 @@ void Isolate::FireCallCompletedCallback() {
v8::MicrotasksPolicy::kAuto; v8::MicrotasksPolicy::kAuto;
if (run_microtasks) RunMicrotasks(); if (run_microtasks) RunMicrotasks();
// Prevent stepping from spilling into the next call made by the embedder.
if (debug()->is_active()) debug()->ClearStepping();
if (call_completed_callbacks_.is_empty()) return; if (call_completed_callbacks_.is_empty()) return;
// Fire callbacks. Increase call depth to prevent recursive callbacks. // Fire callbacks. Increase call depth to prevent recursive callbacks.
......
Check that stepInto at then end of the script go to next user script instead InjectedScriptSource.js. Check that stepInto at then end of the script go to next user script instead InjectedScriptSource.js.
Stack trace: paused at:
boo:0:38 (function boo() { setTimeout(() => 239, 0); #debugger; })()
:0:50
Perform stepInto paused at:
Stack trace: (function boo() { setTimeout(() => 239, 0); debugger; #})()
boo:0:48
:0:50
paused at:
Perform stepInto (function boo() { setTimeout(() => 239, 0); debugger; })()#
Stack trace:
:0:51
paused at:
Perform stepInto (function boo() { setTimeout(() => #239, 0); debugger; })()
Stack trace:
foo:0:12
\ No newline at end of file
...@@ -2,31 +2,26 @@ ...@@ -2,31 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
InspectorTest.log("Check that stepInto at then end of the script go to next user script instead InjectedScriptSource.js."); InspectorTest.log('Check that stepInto at then end of the script go to next user script instead InjectedScriptSource.js.');
InspectorTest.addScript( (async function test() {
`function foo() InspectorTest.setupScriptMap();
{ await Protocol.Debugger.enable();
return 239; Protocol.Runtime.evaluate({expression: '(function boo() { setTimeout(() => 239, 0); debugger; })()\n'});
}`); await waitPauseAndDumpLocation();
Protocol.Debugger.stepInto();
await waitPauseAndDumpLocation();
Protocol.Debugger.stepInto();
await waitPauseAndDumpLocation();
Protocol.Debugger.stepInto();
await waitPauseAndDumpLocation();
await Protocol.Debugger.disable();
InspectorTest.completeTest();
})();
Protocol.Debugger.enable(); async function waitPauseAndDumpLocation() {
Protocol.Debugger.onPaused(debuggerPaused); var message = await Protocol.Debugger.oncePaused();
Protocol.Runtime.evaluate({ "expression": "(function boo() { setTimeout(foo, 0); debugger; })()" }); InspectorTest.log('paused at:');
InspectorTest.logSourceLocation(message.params.callFrames[0].location);
var actions = [ "stepInto", "stepInto", "stepInto" ]; return message;
function debuggerPaused(result)
{
InspectorTest.log("Stack trace:");
for (var callFrame of result.params.callFrames)
InspectorTest.log(callFrame.functionName + ":" + callFrame.location.lineNumber + ":" + callFrame.location.columnNumber);
InspectorTest.log("");
var action = actions.shift();
if (!action) {
Protocol.Debugger.resume().then(InspectorTest.completeTest);
return;
}
InspectorTest.log("Perform " + action);
Protocol.Debugger[action]();
} }
...@@ -915,21 +915,6 @@ break at: ...@@ -915,21 +915,6 @@ break at:
#await p; #await p;
} }
break at:
function return42() {
#return 42;
}
break at:
return 42;
#}
break at:
async function main() {
async function foo#() {
var resolveNested;
break at: break at:
var resolveNested; var resolveNested;
var p = #new Promise(resolve => resolveNested = resolve); var p = #new Promise(resolve => resolveNested = resolve);
......
...@@ -6,11 +6,11 @@ test (foo.js:12:2) ...@@ -6,11 +6,11 @@ test (foo.js:12:2)
(anonymous) (:0:5) (anonymous) (:0:5)
(anonymous) (timeout1.js:0:0) (anonymous) (timeout1.js:0:8)
foo (timeout2.js:1:12) foo (timeout2.js:2:2)
(anonymous) (timeout3.js:0:0) (anonymous) (timeout3.js:0:8)
Running test: testStepOver Running test: testStepOver
...@@ -24,20 +24,14 @@ test (foo.js:13:0) ...@@ -24,20 +24,14 @@ test (foo.js:13:0)
(anonymous) (:0:5) (anonymous) (:0:5)
(anonymous) (timeout1.js:0:0)
(anonymous) (timeout1.js:0:8) (anonymous) (timeout1.js:0:8)
(anonymous) (timeout1.js:0:34) (anonymous) (timeout1.js:0:34)
foo (timeout2.js:1:12)
foo (timeout2.js:2:2) foo (timeout2.js:2:2)
foo (timeout2.js:3:0) foo (timeout2.js:3:0)
(anonymous) (timeout3.js:0:0)
(anonymous) (timeout3.js:0:8) (anonymous) (timeout3.js:0:8)
(anonymous) (timeout3.js:0:34) (anonymous) (timeout3.js:0:34)
...@@ -63,20 +57,14 @@ test (foo.js:13:0) ...@@ -63,20 +57,14 @@ test (foo.js:13:0)
(anonymous) (:0:5) (anonymous) (:0:5)
(anonymous) (timeout1.js:0:0)
(anonymous) (timeout1.js:0:8) (anonymous) (timeout1.js:0:8)
(anonymous) (timeout1.js:0:34) (anonymous) (timeout1.js:0:34)
foo (timeout2.js:1:12)
foo (timeout2.js:2:2) foo (timeout2.js:2:2)
foo (timeout2.js:3:0) foo (timeout2.js:3:0)
(anonymous) (timeout3.js:0:0)
(anonymous) (timeout3.js:0:8) (anonymous) (timeout3.js:0:8)
(anonymous) (timeout3.js:0:34) (anonymous) (timeout3.js:0:34)
......
Checks stepping with more then one context group.
paused at:
#debugger
paused at:
setTimeout(() => #42, 0)
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
InspectorTest.log('Checks stepping with more then one context group.');
(async function test() {
InspectorTest.setupScriptMap();
await Protocol.Debugger.enable();
let contextGroupId = utils.createContextGroup();
await Protocol.Debugger.enable({}, contextGroupId);
Protocol.Runtime.evaluate({expression: 'debugger'});
Protocol.Runtime.evaluate({expression: 'setTimeout(() => { debugger }, 0)'}, contextGroupId);
Protocol.Runtime.evaluate({expression: 'setTimeout(() => 42, 0)'});
await waitPauseAndDumpLocation();
Protocol.Debugger.stepOver();
await Protocol.Debugger.oncePaused();
Protocol.Debugger.stepOver();
await waitPauseAndDumpLocation();
await Protocol.Debugger.disable({}, contextGroupId);
await Protocol.Debugger.disable();
InspectorTest.completeTest();
})();
async function waitPauseAndDumpLocation() {
var message = await Protocol.Debugger.oncePaused();
InspectorTest.log('paused at:');
await InspectorTest.logSourceLocation(message.params.callFrames[0].location);
return message;
}
...@@ -6,6 +6,5 @@ boo ...@@ -6,6 +6,5 @@ boo
-- call foo: -- call foo:
(top) (top)
(top) (top)
(top)
foo foo
(top) (top)
...@@ -343,11 +343,7 @@ class SetTimeoutTask : public AsyncTask { ...@@ -343,11 +343,7 @@ class SetTimeoutTask : public AsyncTask {
v8::Local<v8::Function> function = function_.Get(isolate); v8::Local<v8::Function> function = function_.Get(isolate);
v8::MaybeLocal<v8::Value> result; v8::MaybeLocal<v8::Value> result;
v8_inspector::V8Inspector* inspector =
InspectorClientImpl::InspectorFromContext(context);
if (inspector) inspector->willExecuteScript(context, function->ScriptId());
result = function->Call(context, context->Global(), 0, nullptr); result = function->Call(context, context->Global(), 0, nullptr);
if (inspector) inspector->didExecuteScript(context);
} }
private: private:
......
...@@ -26,7 +26,7 @@ Checks createContext(). ...@@ -26,7 +26,7 @@ Checks createContext().
} }
#debugger; #debugger;
setTimeout(#x => x * 3, 0) setTimeout(x => x #* 3, 0)
Reported script's execution id: 2 Reported script's execution id: 2
{ {
...@@ -51,8 +51,6 @@ Reported script's execution id: 2 ...@@ -51,8 +51,6 @@ Reported script's execution id: 2
} }
#debugger; #debugger;
#debugger; setTimeout(x => x #* 3, 0)
setTimeout(#x => x * 3, 0)
Reported script's execution id: 2 Reported script's execution id: 2
...@@ -241,11 +241,7 @@ void ExecuteStringTask::AsyncRun(v8::Isolate* isolate, ...@@ -241,11 +241,7 @@ void ExecuteStringTask::AsyncRun(v8::Isolate* isolate,
.ToLocal(&script)) .ToLocal(&script))
return; return;
v8::MaybeLocal<v8::Value> result; v8::MaybeLocal<v8::Value> result;
if (inspector_)
inspector_->willExecuteScript(local_context,
script->GetUnboundScript()->GetId());
result = script->Run(local_context); result = script->Run(local_context);
if (inspector_) inspector_->didExecuteScript(local_context);
} else { } else {
v8::Local<v8::Module> module; v8::Local<v8::Module> module;
if (!v8::ScriptCompiler::CompileModule(isolate, &scriptSource) if (!v8::ScriptCompiler::CompileModule(isolate, &scriptSource)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment