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(
if (inspector->compileAndRunInternalScript(context, assertSource)
.ToLocal(&setupFunction) &&
setupFunction->IsFunction()) {
inspector->callInternalFunction(
v8::Local<v8::Function>::Cast(setupFunction), context, console, 0,
nullptr);
v8::MicrotasksScope microtasksScope(
isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::MaybeLocal<v8::Value> result;
result = v8::Local<v8::Function>::Cast(setupFunction)
->Call(context, console, 0, nullptr);
}
if (hasMemoryAttribute)
......
......@@ -198,10 +198,7 @@ V8DebuggerAgentImpl::V8DebuggerAgentImpl(
m_state(state),
m_frontend(frontendChannel),
m_isolate(m_inspector->isolate()),
m_scheduledDebuggerStep(NoStep),
m_javaScriptPauseScheduled(false),
m_recursionLevelForStepOut(0) {
}
m_javaScriptPauseScheduled(false) {}
V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {}
......@@ -253,7 +250,6 @@ Response V8DebuggerAgentImpl::disable() {
m_debugger->setAsyncCallStackDepth(this, 0);
m_continueToLocationBreakpointId = String16();
clearBreakDetails();
m_scheduledDebuggerStep = NoStep;
m_javaScriptPauseScheduled = false;
m_skipAllPauses = false;
m_state->setBoolean(DebuggerAgentState::skipAllPauses, false);
......@@ -688,26 +684,20 @@ void V8DebuggerAgentImpl::clearBreakDetails() {
void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
const String16& breakReason,
std::unique_ptr<protocol::DictionaryValue> data) {
if (!enabled() || m_scheduledDebuggerStep == StepInto ||
m_javaScriptPauseScheduled || isPaused() ||
if (!enabled() || m_javaScriptPauseScheduled || isPaused() ||
!m_debugger->breakpointsActivated())
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));
}
void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() {
DCHECK(enabled());
if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled ||
isPaused())
return;
m_debugger->setPauseOnNextStatement(true);
}
void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
if (m_javaScriptPauseScheduled || isPaused()) return;
popBreakDetails();
if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(false);
if (m_breakReason.empty())
m_debugger->setPauseOnNextStatement(false, m_session->contextGroupId());
}
Response V8DebuggerAgentImpl::pause() {
......@@ -715,14 +705,12 @@ Response V8DebuggerAgentImpl::pause() {
if (m_javaScriptPauseScheduled || isPaused()) return Response::OK();
clearBreakDetails();
m_javaScriptPauseScheduled = true;
m_scheduledDebuggerStep = NoStep;
m_debugger->setPauseOnNextStatement(true);
m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId());
return Response::OK();
}
Response V8DebuggerAgentImpl::resume() {
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
m_scheduledDebuggerStep = NoStep;
m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->continueProgram();
return Response::OK();
......@@ -730,30 +718,22 @@ Response V8DebuggerAgentImpl::resume() {
Response V8DebuggerAgentImpl::stepOver() {
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_debugger->stepOverStatement();
m_debugger->stepOverStatement(m_session->contextGroupId());
return Response::OK();
}
Response V8DebuggerAgentImpl::stepInto() {
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
m_scheduledDebuggerStep = StepInto;
m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->stepIntoStatement();
m_debugger->stepIntoStatement(m_session->contextGroupId());
return Response::OK();
}
Response V8DebuggerAgentImpl::stepOut() {
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
m_scheduledDebuggerStep = StepOut;
m_recursionLevelForStepOut = 1;
m_session->releaseObjectGroup(kBacktraceObjectGroup);
m_debugger->stepOutOfFunction();
m_debugger->stepOutOfFunction(m_session->contextGroupId());
return Response::OK();
}
......@@ -774,8 +754,6 @@ bool V8DebuggerAgentImpl::shouldBreakInScheduledAsyncTask() {
if (!m_stepIntoAsyncCallback) return false;
m_stepIntoAsyncCallback->sendSuccess();
m_stepIntoAsyncCallback.reset();
m_scheduledDebuggerStep = NoStep;
v8::debug::ClearStepping(m_isolate);
return true;
}
......@@ -947,33 +925,6 @@ Response V8DebuggerAgentImpl::setBlackboxedRanges(
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(
std::unique_ptr<Array<CallFrame>>* result) {
if (!isPaused()) {
......@@ -1287,7 +1238,6 @@ void V8DebuggerAgentImpl::didPause(int contextId,
m_frontend.paused(std::move(protocolCallFrames), breakReason,
std::move(breakAuxData), std::move(hitBreakpointIds),
currentAsyncStackTrace());
m_scheduledDebuggerStep = NoStep;
m_javaScriptPauseScheduled = false;
if (!m_continueToLocationBreakpointId.isEmpty()) {
......@@ -1310,12 +1260,11 @@ void V8DebuggerAgentImpl::breakProgram(
std::vector<BreakReason> currentScheduledReason;
currentScheduledReason.swap(m_breakReason);
pushBreakDetails(breakReason, std::move(data));
m_scheduledDebuggerStep = NoStep;
m_debugger->breakProgram();
popBreakDetails();
m_breakReason.swap(currentScheduledReason);
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,
void V8DebuggerAgentImpl::reset() {
if (!enabled()) return;
m_scheduledDebuggerStep = NoStep;
m_blackboxedPositions.clear();
resetBlackboxedStateCache();
m_scripts.clear();
......
......@@ -134,8 +134,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
bool isPromiseRejection, bool isUncaught, bool isOOMBreak);
void didContinue();
void didParseSource(std::unique_ptr<V8DebuggerScript>, bool success);
void willExecuteScript(int scriptId);
void didExecuteScript();
bool isFunctionBlackboxed(const String16& scriptId,
const v8::debug::Location& start,
......@@ -150,14 +148,10 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
private:
void enableImpl();
void schedulePauseOnNextStatementIfSteppingInto();
Response currentCallFrames(
std::unique_ptr<protocol::Array<protocol::Debugger::CallFrame>>*);
std::unique_ptr<protocol::Runtime::StackTrace> currentAsyncStackTrace();
void changeJavaScriptRecursionLevel(int step);
void setPauseOnExceptionsImpl(int);
std::unique_ptr<protocol::Debugger::Location> resolveBreakpoint(
......@@ -182,8 +176,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
protocol::HashMap<String16, std::pair<String16, BreakpointSource>>;
using MuteBreakpoins = protocol::HashMap<String16, std::pair<String16, int>>;
enum DebuggerStep { NoStep = 0, StepInto, StepOver, StepOut };
V8InspectorImpl* m_inspector;
V8Debugger* m_debugger;
V8InspectorSessionImpl* m_session;
......@@ -206,10 +198,7 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
std::unique_ptr<protocol::DictionaryValue> breakAuxData);
void popBreakDetails();
DebuggerStep m_scheduledDebuggerStep;
bool m_javaScriptPauseScheduled;
int m_recursionLevelForStepOut;
bool m_skipAllPauses = false;
std::unique_ptr<V8Regex> m_blackboxPattern;
......
......@@ -328,8 +328,14 @@ void V8Debugger::setPauseOnExceptionsState(
m_pauseOnExceptionsState = pauseOnExceptionsState;
}
void V8Debugger::setPauseOnNextStatement(bool pause) {
void V8Debugger::setPauseOnNextStatement(bool pause, int targetContextGroupId) {
if (isPaused()) return;
DCHECK(targetContextGroupId);
if (!pause && m_targetContextGroupId &&
m_targetContextGroupId != targetContextGroupId) {
return;
}
m_targetContextGroupId = targetContextGroupId;
if (pause)
v8::debug::DebugBreak(m_isolate);
else
......@@ -354,23 +360,29 @@ void V8Debugger::continueProgram() {
m_executionState.Clear();
}
void V8Debugger::stepIntoStatement() {
void V8Debugger::stepIntoStatement(int targetContextGroupId) {
DCHECK(isPaused());
DCHECK(!m_executionState.IsEmpty());
DCHECK(targetContextGroupId);
m_targetContextGroupId = targetContextGroupId;
v8::debug::PrepareStep(m_isolate, v8::debug::StepIn);
continueProgram();
}
void V8Debugger::stepOverStatement() {
void V8Debugger::stepOverStatement(int targetContextGroupId) {
DCHECK(isPaused());
DCHECK(!m_executionState.IsEmpty());
DCHECK(targetContextGroupId);
m_targetContextGroupId = targetContextGroupId;
v8::debug::PrepareStep(m_isolate, v8::debug::StepNext);
continueProgram();
}
void V8Debugger::stepOutOfFunction() {
void V8Debugger::stepOutOfFunction(int targetContextGroupId) {
DCHECK(isPaused());
DCHECK(!m_executionState.IsEmpty());
DCHECK(targetContextGroupId);
m_targetContextGroupId = targetContextGroupId;
v8::debug::PrepareStep(m_isolate, v8::debug::StepOut);
continueProgram();
}
......@@ -504,6 +516,12 @@ void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext,
// Don't allow nested breaks.
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(
m_inspector->contextGroupId(pausedContext));
if (!agent || (agent->skipAllPauses() && !m_scheduledOOMBreak)) return;
......@@ -549,7 +567,10 @@ void V8Debugger::v8OOMCallback(void* data) {
V8Debugger* thisPtr = static_cast<V8Debugger*>(data);
thisPtr->m_isolate->IncreaseHeapLimitForDebugging();
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,
......@@ -660,6 +681,7 @@ void V8Debugger::handleAsyncTaskStepping(v8::Local<v8::Context> context,
if (createdByUser && type == v8::debug::kDebugPromiseCreated) {
if (agent->shouldBreakInScheduledAsyncTask()) {
m_taskWithScheduledBreak = task;
v8::debug::ClearStepping(m_isolate);
}
return;
}
......
......@@ -41,13 +41,14 @@ class V8Debugger : public v8::debug::DebugDelegate {
v8::debug::ExceptionBreakState getPauseOnExceptionsState();
void setPauseOnExceptionsState(v8::debug::ExceptionBreakState);
void setPauseOnNextStatement(bool);
bool canBreakProgram();
void breakProgram();
void continueProgram();
void stepIntoStatement();
void stepOverStatement();
void stepOutOfFunction();
void setPauseOnNextStatement(bool, int targetContextGroupId);
void stepIntoStatement(int targetContextGroupId);
void stepOverStatement(int targetContextGroupId);
void stepOutOfFunction(int targetContextGroupId);
Response setScriptSource(
const String16& sourceID, v8::Local<v8::String> newSource, bool dryRun,
......@@ -162,6 +163,7 @@ class V8Debugger : public v8::debug::DebugDelegate {
bool m_runningNestedMessageLoop;
int m_ignoreScriptParsedEventsCounter;
bool m_scheduledOOMBreak = false;
int m_targetContextGroupId = 0;
using AsyncTaskToStackTrace =
protocol::HashMap<void*, std::unique_ptr<V8StackTraceImpl>>;
......
......@@ -90,52 +90,6 @@ V8ProfilerAgentImpl* V8InspectorImpl::enabledProfilerAgentForGroup(
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::Local<v8::Context> context, v8::Local<v8::String> source) {
v8::Local<v8::UnboundScript> unboundScript;
......@@ -287,17 +241,9 @@ void V8InspectorImpl::resetContextGroup(int contextGroupId) {
void V8InspectorImpl::willExecuteScript(v8::Local<v8::Context> context,
int scriptId) {
if (V8DebuggerAgentImpl* agent =
enabledDebuggerAgentForGroup(contextGroupId(context))) {
agent->willExecuteScript(scriptId);
}
}
void V8InspectorImpl::didExecuteScript(v8::Local<v8::Context> context) {
if (V8DebuggerAgentImpl* agent =
enabledDebuggerAgentForGroup(contextGroupId(context))) {
agent->didExecuteScript();
}
}
void V8InspectorImpl::idleStarted() {
......
......@@ -60,19 +60,8 @@ class V8InspectorImpl : public V8Inspector {
int contextGroupId(v8::Local<v8::Context>);
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::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>,
const String16& code,
const String16& fileName);
......@@ -126,11 +115,6 @@ class V8InspectorImpl : public V8Inspector {
V8ProfilerAgentImpl* enabledProfilerAgentForGroup(int contextGroupId);
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;
V8InspectorClient* m_client;
std::unique_ptr<V8Debugger> m_debugger;
......
......@@ -297,7 +297,9 @@ void V8RuntimeAgentImpl::evaluate(
v8::Local<v8::Script> script;
if (m_inspector->compileScript(scope.context(), expression, String16())
.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);
......@@ -385,8 +387,9 @@ void V8RuntimeAgentImpl::callFunctionOn(
if (m_inspector
->compileScript(scope.context(), "(" + expression + ")", String16())
.ToLocal(&functionScript)) {
maybeFunctionValue =
m_inspector->runCompiledScript(scope.context(), functionScript);
v8::MicrotasksScope microtasksScope(m_inspector->isolate(),
v8::MicrotasksScope::kRunMicrotasks);
maybeFunctionValue = functionScript->Run(scope.context());
}
// Re-initialize after running client's code, as it could have destroyed
// context or session.
......@@ -411,9 +414,13 @@ void V8RuntimeAgentImpl::callFunctionOn(
return;
}
v8::MaybeLocal<v8::Value> maybeResultValue = m_inspector->callFunction(
functionValue.As<v8::Function>(), scope.context(), scope.object(), argc,
argv.get());
v8::MaybeLocal<v8::Value> maybeResultValue;
{
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
// context or session.
response = scope.initialize();
......@@ -620,8 +627,12 @@ void V8RuntimeAgentImpl::runScript(
if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
v8::MaybeLocal<v8::Value> maybeResultValue =
m_inspector->runCompiledScript(scope.context(), script);
v8::MaybeLocal<v8::Value> maybeResultValue;
{
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
// context or session.
......
......@@ -3317,8 +3317,6 @@ void Isolate::FireCallCompletedCallback() {
v8::MicrotasksPolicy::kAuto;
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;
// 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.
Stack trace:
boo:0:38
:0:50
Perform stepInto
Stack trace:
boo:0:48
:0:50
Perform stepInto
Stack trace:
:0:51
Perform stepInto
Stack trace:
foo:0:12
\ No newline at end of file
paused at:
(function boo() { setTimeout(() => 239, 0); #debugger; })()
paused at:
(function boo() { setTimeout(() => 239, 0); debugger; #})()
paused at:
(function boo() { setTimeout(() => 239, 0); debugger; })()#
paused at:
(function boo() { setTimeout(() => #239, 0); debugger; })()
......@@ -2,31 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// 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(
`function foo()
{
return 239;
}`);
(async function test() {
InspectorTest.setupScriptMap();
await Protocol.Debugger.enable();
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();
Protocol.Debugger.onPaused(debuggerPaused);
Protocol.Runtime.evaluate({ "expression": "(function boo() { setTimeout(foo, 0); debugger; })()" });
var actions = [ "stepInto", "stepInto", "stepInto" ];
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]();
async function waitPauseAndDumpLocation() {
var message = await Protocol.Debugger.oncePaused();
InspectorTest.log('paused at:');
InspectorTest.logSourceLocation(message.params.callFrames[0].location);
return message;
}
......@@ -915,21 +915,6 @@ break at:
#await p;
}
break at:
function return42() {
#return 42;
}
break at:
return 42;
#}
break at:
async function main() {
async function foo#() {
var resolveNested;
break at:
var resolveNested;
var p = #new Promise(resolve => resolveNested = resolve);
......
......@@ -6,11 +6,11 @@ test (foo.js:12:2)
(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
......@@ -24,20 +24,14 @@ test (foo.js:13:0)
(anonymous) (:0:5)
(anonymous) (timeout1.js:0:0)
(anonymous) (timeout1.js:0:8)
(anonymous) (timeout1.js:0:34)
foo (timeout2.js:1:12)
foo (timeout2.js:2:2)
foo (timeout2.js:3:0)
(anonymous) (timeout3.js:0:0)
(anonymous) (timeout3.js:0:8)
(anonymous) (timeout3.js:0:34)
......@@ -63,20 +57,14 @@ test (foo.js:13:0)
(anonymous) (:0:5)
(anonymous) (timeout1.js:0:0)
(anonymous) (timeout1.js:0:8)
(anonymous) (timeout1.js:0:34)
foo (timeout2.js:1:12)
foo (timeout2.js:2:2)
foo (timeout2.js:3:0)
(anonymous) (timeout3.js:0:0)
(anonymous) (timeout3.js:0:8)
(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
-- call foo:
(top)
(top)
(top)
foo
(top)
......@@ -343,11 +343,7 @@ class SetTimeoutTask : public AsyncTask {
v8::Local<v8::Function> function = function_.Get(isolate);
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);
if (inspector) inspector->didExecuteScript(context);
}
private:
......
......@@ -26,7 +26,7 @@ Checks createContext().
}
#debugger;
setTimeout(#x => x * 3, 0)
setTimeout(x => x #* 3, 0)
Reported script's execution id: 2
{
......@@ -51,8 +51,6 @@ Reported script's execution id: 2
}
#debugger;
#debugger;
setTimeout(#x => x * 3, 0)
setTimeout(x => x #* 3, 0)
Reported script's execution id: 2
......@@ -241,11 +241,7 @@ void ExecuteStringTask::AsyncRun(v8::Isolate* isolate,
.ToLocal(&script))
return;
v8::MaybeLocal<v8::Value> result;
if (inspector_)
inspector_->willExecuteScript(local_context,
script->GetUnboundScript()->GetId());
result = script->Run(local_context);
if (inspector_) inspector_->didExecuteScript(local_context);
} else {
v8::Local<v8::Module> module;
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