mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 00:35:44 +00:00
Bug 1610416 - Expose SavedFrame frames via debugger server. r=jlast
Differential Revision: https://phabricator.services.mozilla.com/D61517 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
ff0625bca4
commit
1d75bb2c8a
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const { Cu } = require("chrome");
|
||||||
|
const Debugger = require("Debugger");
|
||||||
|
const { assert } = require("devtools/shared/DevToolsUtils");
|
||||||
const { ActorPool } = require("devtools/server/actors/common");
|
const { ActorPool } = require("devtools/server/actors/common");
|
||||||
const { createValueGrip } = require("devtools/server/actors/object/utils");
|
const { createValueGrip } = require("devtools/server/actors/object/utils");
|
||||||
const { ActorClassWithSpec } = require("devtools/shared/protocol");
|
const { ActorClassWithSpec } = require("devtools/shared/protocol");
|
||||||
@ -18,6 +21,49 @@ function formatDisplayName(frame) {
|
|||||||
return `(${frame.type})`;
|
return `(${frame.type})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDeadSavedFrame(savedFrame) {
|
||||||
|
return Cu && Cu.isDeadWrapper(savedFrame);
|
||||||
|
}
|
||||||
|
function isValidSavedFrame(threadActor, savedFrame) {
|
||||||
|
return (
|
||||||
|
!isDeadSavedFrame(savedFrame) &&
|
||||||
|
// If the frame's source is unknown to the debugger, then we ignore it
|
||||||
|
// since the frame likely does not belong to a realm that is marked
|
||||||
|
// as a debuggee.
|
||||||
|
// This check will also fail if the frame would have been known but was
|
||||||
|
// GCed before the debugger was opened on the page.
|
||||||
|
// TODO: Use SavedFrame's security principal to limit non-debuggee frames
|
||||||
|
// and pass all unknown frames to the debugger as a URL with no sourceID.
|
||||||
|
getSavedFrameSource(threadActor, savedFrame)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function getSavedFrameSource(threadActor, savedFrame) {
|
||||||
|
return threadActor.sources.getSourceActorByInternalSourceId(
|
||||||
|
savedFrame.sourceId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function getSavedFrameParent(threadActor, savedFrame) {
|
||||||
|
if (isDeadSavedFrame(savedFrame)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
savedFrame = savedFrame.parent || savedFrame.asyncParent;
|
||||||
|
|
||||||
|
// If the saved frame is a dead wrapper, we don't have any way to keep
|
||||||
|
// stepping through parent frames.
|
||||||
|
if (!savedFrame || isDeadSavedFrame(savedFrame)) {
|
||||||
|
savedFrame = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isValidSavedFrame(threadActor, savedFrame)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return savedFrame;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An actor for a specified stack frame.
|
* An actor for a specified stack frame.
|
||||||
*/
|
*/
|
||||||
@ -25,7 +71,7 @@ const FrameActor = ActorClassWithSpec(frameSpec, {
|
|||||||
/**
|
/**
|
||||||
* Creates the Frame actor.
|
* Creates the Frame actor.
|
||||||
*
|
*
|
||||||
* @param frame Debugger.Frame
|
* @param frame Debugger.Frame|SavedFrame
|
||||||
* The debuggee frame.
|
* The debuggee frame.
|
||||||
* @param threadActor ThreadActor
|
* @param threadActor ThreadActor
|
||||||
* The parent thread actor for this frame.
|
* The parent thread actor for this frame.
|
||||||
@ -81,13 +127,41 @@ const FrameActor = ActorClassWithSpec(frameSpec, {
|
|||||||
* Returns a frame form for use in a protocol message.
|
* Returns a frame form for use in a protocol message.
|
||||||
*/
|
*/
|
||||||
form: function() {
|
form: function() {
|
||||||
|
// SavedFrame actors have their own frame handling.
|
||||||
|
if (!(this.frame instanceof Debugger.Frame)) {
|
||||||
|
// The Frame actor shouldn't be used after evaluation is resumed, so
|
||||||
|
// there shouldn't be an easy way for the saved frame to be referenced
|
||||||
|
// once it has died.
|
||||||
|
assert(!isDeadSavedFrame(this.frame));
|
||||||
|
|
||||||
|
const obj = {
|
||||||
|
actor: this.actorID,
|
||||||
|
// TODO: Bug 1610418 - Consider updating SavedFrame to have a type.
|
||||||
|
type: "dead",
|
||||||
|
asyncCause: this.frame.asyncCause,
|
||||||
|
state: "dead",
|
||||||
|
displayName: this.frame.functionDisplayName,
|
||||||
|
arguments: [],
|
||||||
|
where: {
|
||||||
|
// The frame's source should always be known because
|
||||||
|
// getSavedFrameParent will skip over frames with unknown sources.
|
||||||
|
actor: getSavedFrameSource(this.threadActor, this.frame).actorID,
|
||||||
|
line: this.frame.line,
|
||||||
|
// SavedFrame objects have a 1-based column number, but this API and
|
||||||
|
// Debugger API objects use a 0-based column value.
|
||||||
|
column: this.frame.column - 1,
|
||||||
|
},
|
||||||
|
oldest: !getSavedFrameParent(this.threadActor, this.frame),
|
||||||
|
};
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
const threadActor = this.threadActor;
|
const threadActor = this.threadActor;
|
||||||
const form = {
|
const form = {
|
||||||
actor: this.actorID,
|
actor: this.actorID,
|
||||||
type: this.frame.type,
|
type: this.frame.type,
|
||||||
asyncCause: this.frame.onStack ? null : "await",
|
asyncCause: this.frame.onStack ? null : "await",
|
||||||
|
|
||||||
// This should expand with "dead" when we support SavedFrames.
|
|
||||||
state: this.frame.onStack ? "on-stack" : "suspended",
|
state: this.frame.onStack ? "on-stack" : "suspended",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,3 +213,5 @@ const FrameActor = ActorClassWithSpec(frameSpec, {
|
|||||||
|
|
||||||
exports.FrameActor = FrameActor;
|
exports.FrameActor = FrameActor;
|
||||||
exports.formatDisplayName = formatDisplayName;
|
exports.formatDisplayName = formatDisplayName;
|
||||||
|
exports.getSavedFrameParent = getSavedFrameParent;
|
||||||
|
exports.isValidSavedFrame = isValidSavedFrame;
|
||||||
|
@ -11,6 +11,7 @@ const { ActorPool } = require("devtools/server/actors/common");
|
|||||||
const { createValueGrip } = require("devtools/server/actors/object/utils");
|
const { createValueGrip } = require("devtools/server/actors/object/utils");
|
||||||
const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
|
const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
|
||||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||||
|
const Debugger = require("Debugger");
|
||||||
const { assert, dumpn, reportException } = DevToolsUtils;
|
const { assert, dumpn, reportException } = DevToolsUtils;
|
||||||
const { threadSpec } = require("devtools/shared/specs/thread");
|
const { threadSpec } = require("devtools/shared/specs/thread");
|
||||||
const {
|
const {
|
||||||
@ -54,6 +55,18 @@ loader.lazyRequireGetter(
|
|||||||
"devtools/server/actors/frame",
|
"devtools/server/actors/frame",
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
"getSavedFrameParent",
|
||||||
|
"devtools/server/actors/frame",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
"isValidSavedFrame",
|
||||||
|
"devtools/server/actors/frame",
|
||||||
|
true
|
||||||
|
);
|
||||||
loader.lazyRequireGetter(
|
loader.lazyRequireGetter(
|
||||||
this,
|
this,
|
||||||
"HighlighterEnvironment",
|
"HighlighterEnvironment",
|
||||||
@ -106,6 +119,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||||||
this._activeEventPause = null;
|
this._activeEventPause = null;
|
||||||
this._pauseOverlay = null;
|
this._pauseOverlay = null;
|
||||||
this._priorPause = null;
|
this._priorPause = null;
|
||||||
|
this._frameActorMap = new WeakMap();
|
||||||
|
|
||||||
this._watchpointsMap = new WatchpointMap(this);
|
this._watchpointsMap = new WatchpointMap(this);
|
||||||
|
|
||||||
@ -1218,8 +1232,18 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||||||
const currentFrame = frame;
|
const currentFrame = frame;
|
||||||
frame = null;
|
frame = null;
|
||||||
|
|
||||||
if (currentFrame.older) {
|
if (!(currentFrame instanceof Debugger.Frame)) {
|
||||||
|
frame = getSavedFrameParent(this, currentFrame);
|
||||||
|
} else if (currentFrame.older) {
|
||||||
frame = currentFrame.older;
|
frame = currentFrame.older;
|
||||||
|
} else if (
|
||||||
|
this._options.shouldIncludeSavedFrames &&
|
||||||
|
currentFrame.olderSavedFrame
|
||||||
|
) {
|
||||||
|
frame = currentFrame.olderSavedFrame;
|
||||||
|
if (frame && !isValidSavedFrame(this, frame)) {
|
||||||
|
frame = null;
|
||||||
|
}
|
||||||
} else if (
|
} else if (
|
||||||
this._options.shouldIncludeAsyncLiveFrames &&
|
this._options.shouldIncludeAsyncLiveFrames &&
|
||||||
currentFrame.asyncPromise
|
currentFrame.asyncPromise
|
||||||
@ -1262,9 +1286,14 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||||||
// Return count frames, or all remaining frames if count is not defined.
|
// Return count frames, or all remaining frames if count is not defined.
|
||||||
const frames = [];
|
const frames = [];
|
||||||
for (; frame && (!count || i < start + count); i++, walkToParentFrame()) {
|
for (; frame && (!count || i < start + count); i++, walkToParentFrame()) {
|
||||||
const sourceActor = this.sources.createSourceActor(frame.script.source);
|
// SavedFrame instances don't have direct Debugger.Source object. If
|
||||||
if (!sourceActor) {
|
// there is an active Debugger.Source that represents the SaveFrame's
|
||||||
continue;
|
// source, it will have already been created in the server.
|
||||||
|
if (frame instanceof Debugger.Frame) {
|
||||||
|
const sourceActor = this.sources.createSourceActor(frame.script.source);
|
||||||
|
if (!sourceActor) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const frameActor = this._createFrameActor(frame, i);
|
const frameActor = this._createFrameActor(frame, i);
|
||||||
frames.push(frameActor);
|
frames.push(frameActor);
|
||||||
@ -1494,15 +1523,14 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_createFrameActor: function(frame, depth) {
|
_createFrameActor: function(frame, depth) {
|
||||||
if (frame.actor) {
|
let actor = this._frameActorMap.get(frame);
|
||||||
return frame.actor;
|
if (!actor) {
|
||||||
|
actor = new FrameActor(frame, this, depth);
|
||||||
|
this._frameActors.push(actor);
|
||||||
|
this._framesPool.addActor(actor);
|
||||||
|
|
||||||
|
this._frameActorMap.set(frame, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
const actor = new FrameActor(frame, this, depth);
|
|
||||||
this._frameActors.push(actor);
|
|
||||||
this._framesPool.addActor(actor);
|
|
||||||
frame.actor = actor;
|
|
||||||
|
|
||||||
return actor;
|
return actor;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user