Bug 1505895 - Add handler for changes to a recording/replaying child's state, r=lsmyth.

--HG--
extra : rebase_source : 5cf996fd6d7dfef4a9fc85d697ad35819809ad96
This commit is contained in:
Brian Hackett 2018-11-08 10:06:20 -10:00
parent 2ec0586f2c
commit 4be9981b8d
4 changed files with 47 additions and 10 deletions

View File

@ -76,6 +76,8 @@ ReplayDebugger.prototype = {
return this._sendRequest({ type: "recordingEndpoint" });
},
replayIsRecording: RecordReplayControl.childIsRecording,
addDebuggee() {},
removeAllDebuggees() {},
@ -384,6 +386,14 @@ ReplayDebugger.prototype = {
handler.call(this, this.getNewestFrame()); });
},
get replayingOnPositionChange() {
return this._breakpointKindGetter("PositionChange");
},
set replayingOnPositionChange(handler) {
this._breakpointKindSetter("PositionChange", handler,
() => { handler.call(this); });
},
getNewConsoleMessage() {
const message = this._sendRequest({ type: "getNewConsoleMessage" });
return this._convertConsoleMessage(message);

View File

@ -432,6 +432,14 @@ Middleman_HadRepaintFailure(JSContext* aCx, unsigned aArgc, Value* aVp)
return true;
}
static bool
Middleman_ChildIsRecording(JSContext* aCx, unsigned aArgc, Value* aVp)
{
CallArgs args = CallArgsFromVp(aArgc, aVp);
args.rval().setBoolean(parent::ActiveChildIsRecording());
return true;
}
///////////////////////////////////////////////////////////////////////////////
// Devtools Sandbox
///////////////////////////////////////////////////////////////////////////////
@ -931,6 +939,7 @@ static const JSFunctionSpec gMiddlemanMethods[] = {
JS_FN("maybeSwitchToReplayingChild", Middleman_MaybeSwitchToReplayingChild, 0, 0),
JS_FN("hadRepaint", Middleman_HadRepaint, 2, 0),
JS_FN("hadRepaintFailure", Middleman_HadRepaintFailure, 0, 0),
JS_FN("childIsRecording", Middleman_ChildIsRecording, 0, 0),
JS_FS_END
};

View File

@ -66,7 +66,11 @@ struct BreakpointPosition
// Break when the debugger should pause even if no breakpoint has been
// set: the beginning or end of the replay has been reached, or a time
// warp has reached its destination.
ForcedPause
ForcedPause,
// Break when the child process reaches a checkpoint or we switch between
// recording and replaying child processes.
PositionChange
));
Kind mKind;
@ -120,6 +124,7 @@ struct BreakpointPosition
case ConsoleMessage: return "ConsoleMessage";
case WarpTarget: return "WarpTarget";
case ForcedPause: return "ForcedPause";
case PositionChange: return "PositionChange";
}
MOZ_CRASH("Bad BreakpointPosition kind");
}

View File

@ -14,6 +14,7 @@
#include "js/Proxy.h"
#include "mozilla/dom/ContentProcessMessageManager.h"
#include "InfallibleVector.h"
#include "JSControl.h"
#include "Monitor.h"
#include "ProcessRecordReplay.h"
#include "ProcessRedirect.h"
@ -583,6 +584,10 @@ SpawnReplayingChildren()
AssignMajorCheckpoint(gSecondReplayingChild, CheckpointId::First);
}
// Hit any installed breakpoints with the specified kind.
static void HitBreakpointsWithKind(js::BreakpointPosition::Kind aKind,
bool aRecordingBoundary = false);
// Change the current active child, and select a new role for the old one.
static void
SwitchActiveChild(ChildProcessInfo* aChild, bool aRecoverPosition = true)
@ -608,6 +613,12 @@ SwitchActiveChild(ChildProcessInfo* aChild, bool aRecoverPosition = true)
oldActiveChild->RecoverToCheckpoint(oldActiveChild->MostRecentSavedCheckpoint());
oldActiveChild->SetRole(MakeUnique<ChildRoleStandby>());
}
// Position state is affected when we switch between recording and
// replaying children.
if (aChild->IsRecording() != oldActiveChild->IsRecording()) {
HitBreakpointsWithKind(js::BreakpointPosition::Kind::PositionChange);
}
}
///////////////////////////////////////////////////////////////////////////////
@ -995,9 +1006,6 @@ static bool gChildExecuteBackward = false;
// main thread. This will continue execution in the preferred direction.
static bool gResumeForwardOrBackward = false;
// Hit any breakpoints installed for forced pauses.
static void HitForcedPauseBreakpoints(bool aRecordingBoundary);
static void
MaybeSendRepaintMessage()
{
@ -1050,7 +1058,8 @@ Resume(bool aForward)
// Don't rewind if we are at the beginning of the recording.
if (targetCheckpoint == CheckpointId::Invalid) {
SendMessageToUIProcess("HitRecordingBeginning");
HitForcedPauseBreakpoints(true);
HitBreakpointsWithKind(js::BreakpointPosition::Kind::ForcedPause,
/* aRecordingBoundary = */ true);
return;
}
@ -1077,7 +1086,8 @@ Resume(bool aForward)
MOZ_RELEASE_ASSERT(!gActiveChild->IsRecording());
if (!gRecordingChild) {
SendMessageToUIProcess("HitRecordingEndpoint");
HitForcedPauseBreakpoints(true);
HitBreakpointsWithKind(js::BreakpointPosition::Kind::ForcedPause,
/* aRecordingBoundary = */ true);
return;
}
@ -1142,7 +1152,7 @@ TimeWarp(const js::ExecutionPoint& aTarget)
gActiveChild->WaitUntilPaused();
SendMessageToUIProcess("TimeWarpFinished");
HitForcedPauseBreakpoints(false);
HitBreakpointsWithKind(js::BreakpointPosition::Kind::ForcedPause);
}
void
@ -1189,6 +1199,9 @@ RecvHitCheckpoint(const HitCheckpointMessage& aMsg)
UpdateCheckpointTimes(aMsg);
MaybeUpdateGraphicsAtCheckpoint(aMsg.mCheckpointId);
// Position state is affected when new checkpoints are reached.
HitBreakpointsWithKind(js::BreakpointPosition::Kind::PositionChange);
// Resume either forwards or backwards. Break the resume off into a separate
// runnable, to avoid starving any code already on the stack and waiting for
// the process to pause. Immediately resume if the main thread is blocked.
@ -1247,11 +1260,11 @@ RecvHitBreakpoint(const HitBreakpointMessage& aMsg)
}
static void
HitForcedPauseBreakpoints(bool aRecordingBoundary)
HitBreakpointsWithKind(js::BreakpointPosition::Kind aKind, bool aRecordingBoundary)
{
Vector<uint32_t> breakpoints;
gActiveChild->GetMatchingInstalledBreakpoints([=](js::BreakpointPosition::Kind aKind) {
return aKind == js::BreakpointPosition::ForcedPause;
gActiveChild->GetMatchingInstalledBreakpoints([=](js::BreakpointPosition::Kind aInstalled) {
return aInstalled == aKind;
}, breakpoints);
if (!breakpoints.empty()) {
uint32_t* newBreakpoints = new uint32_t[breakpoints.length()];