Bug 1479058 Part 6 - ReplayDebugger and server/client changes to support time warps, r=jimb.

--HG--
extra : rebase_source : 5972ae72f0601e3daa2506e1be3844dc77e3bafc
This commit is contained in:
Brian Hackett 2018-08-02 23:30:19 +00:00
Родитель cb73c42b70
Коммит 9844ce064b
3 изменённых файлов: 65 добавлений и 3 удалений

Просмотреть файл

@ -61,6 +61,7 @@ ReplayDebugger.prototype = {
canRewind: RecordReplayControl.canRewind,
replayResumeBackward() { RecordReplayControl.resume(/* forward = */ false); },
replayResumeForward() { RecordReplayControl.resume(/* forward = */ true); },
replayTimeWarp: RecordReplayControl.timeWarp,
replayPause: RecordReplayControl.pause,
addDebuggee() {},
@ -293,6 +294,14 @@ ReplayDebugger.prototype = {
}
},
get replayingOnForcedPause() {
return this._breakpointKindGetter("ForcedPause");
},
set replayingOnForcedPause(handler) {
this._breakpointKindSetter("ForcedPause", handler,
() => handler.call(this, this.getNewestFrame()));
},
clearAllBreakpoints: NYI,
}; // ReplayDebugger.prototype

Просмотреть файл

@ -108,6 +108,9 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
this._dbg.onDebuggerStatement = this.onDebuggerStatement;
this._dbg.onNewScript = this.onNewScript;
this._dbg.on("newGlobal", this.onNewGlobal);
if (this._dbg.replaying) {
this._dbg.replayingOnForcedPause = this.replayingOnForcedPause.bind(this);
}
// Keep the debugger disabled until a client attaches.
this._dbg.enabled = this._state != "detached";
}
@ -645,13 +648,18 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
_handleResumeLimit: async function(request) {
const steppingType = request.resumeLimit.type;
const rewinding = request.rewind;
if (!["break", "step", "next", "finish"].includes(steppingType)) {
if (!["break", "step", "next", "finish", "warp"].includes(steppingType)) {
return Promise.reject({
error: "badParameterType",
message: "Unknown resumeLimit type"
});
}
if (steppingType == "warp") {
// Time warp resume limits are handled by the caller.
return true;
}
const generatedLocation = this.sources.getFrameLocation(this.youngestFrame);
const originalLocation = await this.sources.getOriginalLocation(generatedLocation);
const { onEnterFrame, onPop, onStep } = this._makeSteppingHooks(
@ -660,7 +668,8 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
rewinding
);
// Make sure there is still a frame on the stack if we are to continue stepping.
// Make sure there is still a frame on the stack if we are to continue
// stepping.
const stepFrame = this._getNextStepFrame(this.youngestFrame, rewinding);
if (stepFrame) {
switch (steppingType) {
@ -799,7 +808,9 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
// When replaying execution in a separate process we need to explicitly
// notify that process when to resume execution.
if (this.dbg.replaying) {
if (rewinding) {
if (request && request.resumeLimit && request.resumeLimit.type == "warp") {
this.dbg.replayTimeWarp(request.resumeLimit.target);
} else if (rewinding) {
this.dbg.replayResumeBackward();
} else {
this.dbg.replayResumeForward();
@ -1635,6 +1646,29 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
return { skip };
},
/**
* A function that the engine calls when replay has hit a point where it will
* pause, even if no breakpoint has been set. Such points include hitting the
* beginning or end of the replay, or reaching the target of a time warp.
*
* @param frame Debugger.Frame
* The youngest stack frame, or null.
*/
replayingOnForcedPause: function(frame) {
if (frame) {
this._pauseAndRespond(frame, { type: "replayForcedPause" });
} else {
const packet = this._paused(frame);
if (!packet) {
return;
}
packet.why = "replayForcedPause";
this.conn.send(packet);
this._pushThreadPause();
}
},
/**
* A function that the engine calls when an exception has been thrown and has
* propagated to the specified frame.

Просмотреть файл

@ -245,6 +245,25 @@ ThreadClient.prototype = {
return this._doInterrupt("onNext", onResponse);
},
/**
* Warp through time to an execution point in the past or future.
*
* @param object aTarget
* Description of the warp destination.
* @param function aOnResponse
* Called with the response packet.
*/
timeWarp: function(target, onResponse) {
const warp = () => {
this._doResume({ type: "warp", target }, true, onResponse);
};
if (this.paused) {
warp();
} else {
this.interrupt(warp);
}
},
/**
* Interrupt a running thread.
*