зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1573970 - Pause on debugger statements when using web replay, r=loganfsmyth.
Differential Revision: https://phabricator.services.mozilla.com/D42243 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
0ce65ed8c4
Коммит
3281985555
|
@ -13,14 +13,7 @@ support-files =
|
|||
!/devtools/client/debugger/test/mochitest/helpers.js
|
||||
!/devtools/client/debugger/test/mochitest/helpers/context.js
|
||||
!/devtools/client/inspector/test/shared-head.js
|
||||
examples/doc_rr_basic.html
|
||||
examples/doc_rr_continuous.html
|
||||
examples/doc_rr_logs.html
|
||||
examples/doc_rr_error.html
|
||||
examples/doc_control_flow.html
|
||||
examples/doc_inspector_basic.html
|
||||
examples/doc_inspector_styles.html
|
||||
examples/styles.css
|
||||
examples/*
|
||||
|
||||
[browser_dbg_rr_breakpoints-01.js]
|
||||
[browser_dbg_rr_breakpoints-02.js]
|
||||
|
@ -28,6 +21,7 @@ support-files =
|
|||
[browser_dbg_rr_breakpoints-04.js]
|
||||
[browser_dbg_rr_breakpoints-05.js]
|
||||
[browser_dbg_rr_breakpoints-06.js]
|
||||
[browser_dbg_rr_breakpoints-07.js]
|
||||
[browser_dbg_rr_record.js]
|
||||
[browser_dbg_rr_stepping-01.js]
|
||||
[browser_dbg_rr_stepping-02.js]
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Pausing at a debugger statement on startup confuses the debugger.
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Unknown source actor/);
|
||||
|
||||
// Test interaction of breakpoints with debugger statements.
|
||||
add_task(async function() {
|
||||
const dbg = await attachRecordingDebugger("doc_debugger_statements.html");
|
||||
const { threadFront } = dbg;
|
||||
|
||||
await waitForPaused(dbg);
|
||||
const { frames } = await threadFront.getFrames(0, 1);
|
||||
ok(frames[0].where.line == 6, "Paused at first debugger statement");
|
||||
|
||||
const bp = await setBreakpoint(
|
||||
threadFront,
|
||||
"doc_debugger_statements.html",
|
||||
7
|
||||
);
|
||||
await resumeToLine(threadFront, 7);
|
||||
await resumeToLine(threadFront, 8);
|
||||
await threadFront.removeBreakpoint(bp);
|
||||
await rewindToLine(threadFront, 6);
|
||||
await resumeToLine(threadFront, 8);
|
||||
|
||||
await shutdownDebugger(dbg);
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
<html lang="en" dir="ltr">
|
||||
<body>
|
||||
<div id="maindiv" style="padding-top:50px">Hello World!</div>
|
||||
</body>
|
||||
<script>
|
||||
debugger;
|
||||
document.getElementById("maindiv").innerHTML = "Foobar!";
|
||||
debugger;
|
||||
</script>
|
||||
</html>
|
|
@ -265,8 +265,11 @@ ChildProcess.prototype = {
|
|||
// Get an estimate of the amount of time required for this child to reach an
|
||||
// execution point.
|
||||
timeToReachPoint(point) {
|
||||
let startDelay = 0,
|
||||
startPoint = this.lastPausePoint;
|
||||
let startDelay = 0;
|
||||
let startPoint = this.lastPausePoint;
|
||||
if (!startPoint) {
|
||||
startPoint = checkpointExecutionPoint(FirstCheckpointId);
|
||||
}
|
||||
if (!this.paused) {
|
||||
if (this.manifest.expectedDuration) {
|
||||
const elapsed = Date.now() - this.manifestSendTime;
|
||||
|
@ -493,6 +496,9 @@ function CheckpointInfo() {
|
|||
|
||||
// If the checkpoint is saved and scanned, the duration of the scan.
|
||||
this.scanDuration = null;
|
||||
|
||||
// If the checkpoint is saved, any debugger statement hits in its region.
|
||||
this.debuggerStatements = [];
|
||||
}
|
||||
|
||||
function getCheckpointInfo(id) {
|
||||
|
@ -1169,6 +1175,9 @@ async function finishResume() {
|
|||
);
|
||||
}
|
||||
|
||||
// Always pause at debugger statements, as if they are breakpoint hits.
|
||||
hits = hits.concat(getCheckpointInfo(checkpoint).debuggerStatements);
|
||||
|
||||
const hit = findClosestPoint(
|
||||
hits,
|
||||
gPausePoint,
|
||||
|
@ -1442,6 +1451,7 @@ function handleResumeManifestResponse({
|
|||
duration,
|
||||
consoleMessages,
|
||||
scripts,
|
||||
debuggerStatements,
|
||||
}) {
|
||||
if (!point.position) {
|
||||
addCheckpoint(point.checkpoint - 1, duration);
|
||||
|
@ -1461,6 +1471,11 @@ function handleResumeManifestResponse({
|
|||
queuePauseData(msg.executionPoint, /* trackCached */ true);
|
||||
}
|
||||
});
|
||||
|
||||
for (const point of debuggerStatements) {
|
||||
const checkpoint = getSavedCheckpoint(point.checkpoint);
|
||||
getCheckpointInfo(checkpoint).debuggerStatements.push(point);
|
||||
}
|
||||
}
|
||||
|
||||
// If necessary, continue executing in the main child.
|
||||
|
@ -1486,7 +1501,11 @@ function maybeResumeRecording() {
|
|||
return;
|
||||
}
|
||||
gMainChild.sendManifest({
|
||||
contents: { kind: "resume", breakpoints: gBreakpoints },
|
||||
contents: {
|
||||
kind: "resume",
|
||||
breakpoints: gBreakpoints,
|
||||
pauseOnDebuggerStatement: true,
|
||||
},
|
||||
onFinished(response) {
|
||||
handleResumeManifestResponse(response);
|
||||
|
||||
|
@ -1750,7 +1769,11 @@ const gControl = {
|
|||
// We can only flush the recording at checkpoints, so we need to send the
|
||||
// main child forward and pause/flush ASAP.
|
||||
gMainChild.sendManifest({
|
||||
contents: { kind: "resume", breakpoints: [] },
|
||||
contents: {
|
||||
kind: "resume",
|
||||
breakpoints: [],
|
||||
pauseOnDebuggerStatement: false,
|
||||
},
|
||||
onFinished(response) {
|
||||
handleResumeManifestResponse(response);
|
||||
},
|
||||
|
@ -1872,6 +1895,16 @@ const gControl = {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
isPausedAtDebuggerStatement() {
|
||||
const point = gControl.pausePoint();
|
||||
if (point) {
|
||||
const checkpoint = getSavedCheckpoint(point.checkpoint);
|
||||
const { debuggerStatements } = getCheckpointInfo(checkpoint);
|
||||
return pointArrayIncludes(debuggerStatements, point);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -285,6 +285,14 @@ ReplayDebugger.prototype = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
this._control.isPausedAtDebuggerStatement() &&
|
||||
this.onDebuggerStatement
|
||||
) {
|
||||
this._capturePauseData();
|
||||
this.onDebuggerStatement(this.getNewestFrame());
|
||||
}
|
||||
}
|
||||
|
||||
// If no handlers entered a thread-wide pause (resetting this._direction)
|
||||
|
|
|
@ -655,6 +655,7 @@ const gOnPopFilters = [];
|
|||
function clearPositionHandlers() {
|
||||
dbg.clearAllBreakpoints();
|
||||
dbg.onEnterFrame = undefined;
|
||||
dbg.onDebuggerStatement = undefined;
|
||||
|
||||
gHasEnterFrameHandler = false;
|
||||
gPendingPcHandlers.length = 0;
|
||||
|
@ -908,13 +909,22 @@ let gManifest;
|
|||
// manifest started executing.
|
||||
let gManifestStartTime;
|
||||
|
||||
// Points of any debugger statements that need to be flushed to the middleman.
|
||||
const gNewDebuggerStatements = [];
|
||||
|
||||
// Whether to pause on debugger statements when running forward.
|
||||
let gPauseOnDebuggerStatement = false;
|
||||
|
||||
// Handlers that run when a manifest is first received. This must be specified
|
||||
// for all manifests.
|
||||
const gManifestStartHandlers = {
|
||||
resume({ breakpoints }) {
|
||||
resume({ breakpoints, pauseOnDebuggerStatement }) {
|
||||
RecordReplayControl.resumeExecution();
|
||||
gManifestStartTime = RecordReplayControl.currentExecutionTime();
|
||||
breakpoints.forEach(ensurePositionHandler);
|
||||
|
||||
gPauseOnDebuggerStatement = pauseOnDebuggerStatement;
|
||||
dbg.onDebuggerStatement = debuggerStatementHit;
|
||||
},
|
||||
|
||||
restoreCheckpoint({ target }) {
|
||||
|
@ -1044,18 +1054,24 @@ function currentScriptedExecutionPoint() {
|
|||
});
|
||||
}
|
||||
|
||||
function finishResume(point) {
|
||||
RecordReplayControl.manifestFinished({
|
||||
point,
|
||||
duration: RecordReplayControl.currentExecutionTime() - gManifestStartTime,
|
||||
consoleMessages: gNewConsoleMessages,
|
||||
scripts: gNewScripts,
|
||||
debuggerStatements: gNewDebuggerStatements,
|
||||
});
|
||||
gNewConsoleMessages.length = 0;
|
||||
gNewScripts.length = 0;
|
||||
gNewDebuggerStatements.length = 0;
|
||||
}
|
||||
|
||||
// Handlers that run after a checkpoint is reached to see if the manifest has
|
||||
// finished. This does not need to be specified for all manifests.
|
||||
const gManifestFinishedAfterCheckpointHandlers = {
|
||||
resume(_, point) {
|
||||
RecordReplayControl.manifestFinished({
|
||||
point,
|
||||
duration: RecordReplayControl.currentExecutionTime() - gManifestStartTime,
|
||||
consoleMessages: gNewConsoleMessages,
|
||||
scripts: gNewScripts,
|
||||
});
|
||||
gNewConsoleMessages.length = 0;
|
||||
gNewScripts.length = 0;
|
||||
finishResume(point);
|
||||
},
|
||||
|
||||
runToPoint({ endpoint }, point) {
|
||||
|
@ -1136,11 +1152,7 @@ function AfterCheckpoint(id, restoredCheckpoint) {
|
|||
const gManifestPositionHandlers = {
|
||||
resume(manifest, point) {
|
||||
clearPositionHandlers();
|
||||
RecordReplayControl.manifestFinished({
|
||||
point,
|
||||
consoleMessages: gNewConsoleMessages,
|
||||
scripts: gNewScripts,
|
||||
});
|
||||
finishResume(point);
|
||||
},
|
||||
|
||||
runToPoint({ endpoint }, point) {
|
||||
|
@ -1161,6 +1173,17 @@ function positionHit(position, frame) {
|
|||
}
|
||||
}
|
||||
|
||||
function debuggerStatementHit() {
|
||||
assert(gManifest.kind == "resume");
|
||||
const point = currentScriptedExecutionPoint();
|
||||
gNewDebuggerStatements.push(point);
|
||||
|
||||
if (gPauseOnDebuggerStatement) {
|
||||
clearPositionHandlers();
|
||||
finishResume(point);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Handler Helpers
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Загрузка…
Ссылка в новой задаче