mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1039952 - Part 0: Make the parent actors manage the set of debuggees. r=fitzgen
This commit is contained in:
parent
6c42c43a3f
commit
6ba4a89244
@ -112,7 +112,7 @@ EventEmitter.prototype = {
|
||||
|
||||
/**
|
||||
* Emit an event. All arguments to this method will
|
||||
* be sent to listner functions.
|
||||
* be sent to listener functions.
|
||||
*/
|
||||
emit: function EventEmitter_emit(aEvent) {
|
||||
this.logEvent(aEvent, arguments);
|
||||
|
@ -8,3 +8,4 @@ libs::
|
||||
$(INSTALL) $(IFLAGS1) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
|
||||
$(INSTALL) $(IFLAGS1) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools/server
|
||||
$(INSTALL) $(IFLAGS1) $(srcdir)/actors/*.js $(FINAL_TARGET)/modules/devtools/server/actors
|
||||
$(INSTALL) $(IFLAGS1) $(srcdir)/actors/utils/*.js $(FINAL_TARGET)/modules/devtools/server/actors/utils
|
||||
|
@ -63,7 +63,7 @@ let MemoryActor = protocol.ActorClass({
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
let url = this.tabActor.url;
|
||||
console.error("Error getting size of "+url);
|
||||
console.error("Error getting size of " + url);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -11,6 +11,7 @@ const Services = require("Services");
|
||||
const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/server/actors/common");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const { dumpProtocolSpec } = require("devtools/server/protocol");
|
||||
const makeDebugger = require("./utils/make-debugger");
|
||||
|
||||
/* Root actor for the remote debugging protocol. */
|
||||
|
||||
@ -92,6 +93,12 @@ function RootActor(aConnection, aParameters) {
|
||||
this._onTabListChanged = this.onTabListChanged.bind(this);
|
||||
this._onAddonListChanged = this.onAddonListChanged.bind(this);
|
||||
this._extraActors = {};
|
||||
|
||||
// This creates a Debugger instance for chrome debugging all globals.
|
||||
this.makeDebugger = makeDebugger.bind(null, {
|
||||
findDebuggees: dbg => dbg.findAllGlobals(),
|
||||
shouldAddNewGlobalAsDebuggee: () => true
|
||||
});
|
||||
}
|
||||
|
||||
RootActor.prototype = {
|
||||
|
@ -16,6 +16,7 @@ const { SourceMapConsumer, SourceMapGenerator } = require("source-map");
|
||||
const promise = require("promise");
|
||||
const Debugger = require("Debugger");
|
||||
const xpcInspector = require("xpcInspector");
|
||||
const mapURIToAddonID = require("./utils/map-uri-to-addon-id");
|
||||
|
||||
const { defer, resolve, reject, all } = require("devtools/toolkit/deprecated-sync-thenables");
|
||||
const { CssLogic } = require("devtools/styleinspector/css-logic");
|
||||
@ -24,8 +25,6 @@ DevToolsUtils.defineLazyGetter(this, "NetUtil", () => {
|
||||
return Cu.import("resource://gre/modules/NetUtil.jsm", {}).NetUtil;
|
||||
});
|
||||
|
||||
let B2G_ID = "{3c2e2abc-06d4-11e1-ac3b-374f68613e61}";
|
||||
|
||||
let TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array",
|
||||
"Uint32Array", "Int8Array", "Int16Array", "Int32Array", "Float32Array",
|
||||
"Float64Array"];
|
||||
@ -34,34 +33,6 @@ let TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array",
|
||||
// collections, etc.
|
||||
let OBJECT_PREVIEW_MAX_ITEMS = 10;
|
||||
|
||||
let addonManager = null;
|
||||
|
||||
/**
|
||||
* This is a wrapper around amIAddonManager.mapURIToAddonID which always returns
|
||||
* false on B2G to avoid loading the add-on manager there and reports any
|
||||
* exceptions rather than throwing so that the caller doesn't have to worry
|
||||
* about them.
|
||||
*/
|
||||
function mapURIToAddonID(uri, id) {
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT ||
|
||||
(Services.appinfo.ID || undefined) == B2G_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addonManager) {
|
||||
addonManager = Cc["@mozilla.org/addons/integration;1"].
|
||||
getService(Ci.amIAddonManager);
|
||||
}
|
||||
|
||||
try {
|
||||
return addonManager.mapURIToAddonID(uri, id);
|
||||
}
|
||||
catch (e) {
|
||||
DevToolsUtils.reportException("mapURIToAddonID", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BreakpointStore objects keep track of all breakpoints that get set so that we
|
||||
* can reset them when the same script is introduced to the thread again (such
|
||||
@ -481,41 +452,53 @@ EventLoop.prototype = {
|
||||
/**
|
||||
* JSD2 actors.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a ThreadActor.
|
||||
*
|
||||
* ThreadActors manage a JSInspector object and manage execution/inspection
|
||||
* of debuggees.
|
||||
*
|
||||
* @param aHooks object
|
||||
* An object with preNest and postNest methods for calling when entering
|
||||
* and exiting a nested event loop.
|
||||
* @param aParent object
|
||||
* This |ThreadActor|'s parent actor. It must implement the following
|
||||
* properties:
|
||||
* - url: The URL string of the debuggee.
|
||||
* - window: The global window object.
|
||||
* - preNest: Function called before entering a nested event loop.
|
||||
* - postNest: Function called after exiting a nested event loop.
|
||||
* - makeDebugger: A function that takes no arguments and instantiates
|
||||
* a Debugger that manages its globals on its own.
|
||||
* @param aGlobal object [optional]
|
||||
* An optional (for content debugging only) reference to the content
|
||||
* window.
|
||||
*/
|
||||
function ThreadActor(aHooks, aGlobal)
|
||||
function ThreadActor(aParent, aGlobal)
|
||||
{
|
||||
this._state = "detached";
|
||||
this._frameActors = [];
|
||||
this._hooks = aHooks;
|
||||
this.global = aGlobal;
|
||||
// A map of actorID -> actor for breakpoints created and managed by the server.
|
||||
this._hiddenBreakpoints = new Map();
|
||||
|
||||
this.findGlobals = this.globalManager.findGlobals.bind(this);
|
||||
this.onNewGlobal = this.globalManager.onNewGlobal.bind(this);
|
||||
this.onNewSource = this.onNewSource.bind(this);
|
||||
this._allEventsListener = this._allEventsListener.bind(this);
|
||||
this._parent = aParent;
|
||||
this._dbg = null;
|
||||
this._gripDepth = 0;
|
||||
this._threadLifetimePool = null;
|
||||
this._tabClosed = false;
|
||||
|
||||
this._options = {
|
||||
useSourceMaps: false,
|
||||
autoBlackBox: false
|
||||
};
|
||||
|
||||
this._gripDepth = 0;
|
||||
this._threadLifetimePool = null;
|
||||
this._tabClosed = false;
|
||||
// A map of actorID -> actor for breakpoints created and managed by the
|
||||
// server.
|
||||
this._hiddenBreakpoints = new Map();
|
||||
|
||||
this.global = aGlobal;
|
||||
|
||||
this._allEventsListener = this._allEventsListener.bind(this);
|
||||
this.onNewGlobal = this.onNewGlobal.bind(this);
|
||||
this.onNewSource = this.onNewSource.bind(this);
|
||||
this.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
|
||||
this.onDebuggerStatement = this.onDebuggerStatement.bind(this);
|
||||
this.onNewScript = this.onNewScript.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -530,6 +513,23 @@ ThreadActor.prototype = {
|
||||
|
||||
actorPrefix: "context",
|
||||
|
||||
get dbg() {
|
||||
if (!this._dbg) {
|
||||
this._dbg = this._parent.makeDebugger();
|
||||
this._dbg.uncaughtExceptionHook = this.uncaughtExceptionHook;
|
||||
this._dbg.onDebuggerStatement = this.onDebuggerStatement;
|
||||
this._dbg.onNewScript = this.onNewScript;
|
||||
this._dbg.on("newGlobal", this.onNewGlobal);
|
||||
// Keep the debugger disabled until a client attaches.
|
||||
this._dbg.enabled = this._state != "detached";
|
||||
}
|
||||
return this._dbg;
|
||||
},
|
||||
|
||||
get globalDebugObject() {
|
||||
return this.dbg.makeGlobalObjectReference(this._parent.window);
|
||||
},
|
||||
|
||||
get state() { return this._state; },
|
||||
get attached() this.state == "attached" ||
|
||||
this.state == "running" ||
|
||||
@ -618,126 +618,23 @@ ThreadActor.prototype = {
|
||||
* Remove all debuggees and clear out the thread's sources.
|
||||
*/
|
||||
clearDebuggees: function () {
|
||||
if (this.dbg) {
|
||||
if (this._dbg) {
|
||||
this.dbg.removeAllDebuggees();
|
||||
}
|
||||
this._sources = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a debuggee global to the Debugger object.
|
||||
*
|
||||
* @returns the Debugger.Object that corresponds to the global.
|
||||
* Listener for our |Debugger|'s "newGlobal" event.
|
||||
*/
|
||||
addDebuggee: function (aGlobal) {
|
||||
let globalDebugObject;
|
||||
try {
|
||||
globalDebugObject = this.dbg.addDebuggee(aGlobal);
|
||||
} catch (e) {
|
||||
// Ignore attempts to add the debugger's compartment as a debuggee.
|
||||
dumpn("Ignoring request to add the debugger's compartment as a debuggee");
|
||||
}
|
||||
return globalDebugObject;
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the Debugger.
|
||||
*/
|
||||
_initDebugger: function () {
|
||||
this.dbg = new Debugger();
|
||||
this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
|
||||
this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this);
|
||||
this.dbg.onNewScript = this.onNewScript.bind(this);
|
||||
this.dbg.onNewGlobalObject = this.globalManager.onNewGlobal.bind(this);
|
||||
// Keep the debugger disabled until a client attaches.
|
||||
this.dbg.enabled = this._state != "detached";
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a debuggee global from the JSInspector.
|
||||
*/
|
||||
removeDebugee: function (aGlobal) {
|
||||
try {
|
||||
this.dbg.removeDebuggee(aGlobal);
|
||||
} catch(ex) {
|
||||
// XXX: This debuggee has code currently executing on the stack,
|
||||
// we need to save this for later.
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the provided window and all windows in its frame tree as debuggees.
|
||||
*
|
||||
* @returns the Debugger.Object that corresponds to the window.
|
||||
*/
|
||||
_addDebuggees: function (aWindow) {
|
||||
let globalDebugObject = this.addDebuggee(aWindow);
|
||||
let frames = aWindow.frames;
|
||||
if (frames) {
|
||||
for (let i = 0; i < frames.length; i++) {
|
||||
this._addDebuggees(frames[i]);
|
||||
}
|
||||
}
|
||||
return globalDebugObject;
|
||||
},
|
||||
|
||||
/**
|
||||
* An object that will be used by ThreadActors to tailor their behavior
|
||||
* depending on the debugging context being required (chrome or content).
|
||||
*/
|
||||
globalManager: {
|
||||
findGlobals: function () {
|
||||
const { getContentGlobals } = require("devtools/server/content-globals");
|
||||
|
||||
this.globalDebugObject = this._addDebuggees(this.global);
|
||||
|
||||
// global may not be a window
|
||||
try {
|
||||
getContentGlobals({
|
||||
'inner-window-id': getInnerId(this.global)
|
||||
}).forEach(this.addDebuggee.bind(this));
|
||||
}
|
||||
catch(e) {}
|
||||
},
|
||||
|
||||
/**
|
||||
* A function that the engine calls when a new global object
|
||||
* (for example a sandbox) has been created.
|
||||
*
|
||||
* @param aGlobal Debugger.Object
|
||||
* The new global object that was created.
|
||||
*/
|
||||
onNewGlobal: function (aGlobal) {
|
||||
let useGlobal = (aGlobal.hostAnnotations &&
|
||||
aGlobal.hostAnnotations.type == "document" &&
|
||||
aGlobal.hostAnnotations.element === this.global);
|
||||
|
||||
// check if the global is a sdk page-mod sandbox
|
||||
if (!useGlobal) {
|
||||
let metadata = {};
|
||||
let id = "";
|
||||
try {
|
||||
id = getInnerId(this.global);
|
||||
metadata = Cu.getSandboxMetadata(aGlobal.unsafeDereference());
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
useGlobal = (metadata['inner-window-id'] && metadata['inner-window-id'] == id);
|
||||
}
|
||||
|
||||
// Content debugging only cares about new globals in the contant window,
|
||||
// like iframe children.
|
||||
if (useGlobal) {
|
||||
this.addDebuggee(aGlobal);
|
||||
// Notify the client.
|
||||
this.conn.send({
|
||||
from: this.actorID,
|
||||
type: "newGlobal",
|
||||
// TODO: after bug 801084 lands see if we need to JSONify this.
|
||||
hostAnnotations: aGlobal.hostAnnotations
|
||||
});
|
||||
}
|
||||
}
|
||||
onNewGlobal: function (aGlobal) {
|
||||
// Notify the client.
|
||||
this.conn.send({
|
||||
from: this.actorID,
|
||||
type: "newGlobal",
|
||||
// TODO: after bug 801084 lands see if we need to JSONify this.
|
||||
hostAnnotations: aGlobal.hostAnnotations
|
||||
});
|
||||
},
|
||||
|
||||
disconnect: function () {
|
||||
@ -759,11 +656,11 @@ ThreadActor.prototype = {
|
||||
this._prettyPrintWorker = null;
|
||||
}
|
||||
|
||||
if (!this.dbg) {
|
||||
if (!this._dbg) {
|
||||
return;
|
||||
}
|
||||
this.dbg.enabled = false;
|
||||
this.dbg = null;
|
||||
this._dbg.enabled = false;
|
||||
this._dbg = null;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -792,15 +689,12 @@ ThreadActor.prototype = {
|
||||
// Initialize an event loop stack. This can't be done in the constructor,
|
||||
// because this.conn is not yet initialized by the actor pool at that time.
|
||||
this._nestedEventLoops = new EventLoopStack({
|
||||
hooks: this._hooks,
|
||||
hooks: this._parent,
|
||||
connection: this.conn,
|
||||
thread: this
|
||||
});
|
||||
|
||||
if (!this.dbg) {
|
||||
this._initDebugger();
|
||||
}
|
||||
this.findGlobals();
|
||||
this.dbg.addDebuggees();
|
||||
this.dbg.enabled = true;
|
||||
try {
|
||||
// Put ourselves in the paused state.
|
||||
@ -1132,8 +1026,8 @@ ThreadActor.prototype = {
|
||||
// different tabs or multiple debugger clients connected to the same tab)
|
||||
// only allow resumption in a LIFO order.
|
||||
if (this._nestedEventLoops.size && this._nestedEventLoops.lastPausedUrl
|
||||
&& (this._nestedEventLoops.lastPausedUrl !== this._hooks.url
|
||||
|| this._nestedEventLoops.lastConnection !== this.conn)) {
|
||||
&& (this._nestedEventLoops.lastPausedUrl !== this._parent.url
|
||||
|| this._nestedEventLoops.lastConnection !== this.conn)) {
|
||||
return {
|
||||
error: "wrongOrder",
|
||||
message: "trying to resume in the wrong order.",
|
||||
@ -1925,6 +1819,7 @@ ThreadActor.prototype = {
|
||||
aFrame.onStep = undefined;
|
||||
aFrame.onPop = undefined;
|
||||
}
|
||||
|
||||
// Clear DOM event breakpoints.
|
||||
// XPCShell tests don't use actual DOM windows for globals and cause
|
||||
// removeListenerForAllEvents to throw.
|
||||
@ -4836,13 +4731,13 @@ Object.defineProperty(Debugger.Frame.prototype, "line", {
|
||||
* is associated. (Currently unused, but required to make this
|
||||
* constructor usable with addGlobalActor.)
|
||||
*
|
||||
* @param aHooks object
|
||||
* An object with preNest and postNest methods for calling when entering
|
||||
* and exiting a nested event loop.
|
||||
* @param aParent object
|
||||
* This actor's parent actor. See ThreadActor for a list of expected
|
||||
* properties.
|
||||
*/
|
||||
function ChromeDebuggerActor(aConnection, aHooks)
|
||||
function ChromeDebuggerActor(aConnection, aParent)
|
||||
{
|
||||
ThreadActor.call(this, aHooks);
|
||||
ThreadActor.call(this, aParent);
|
||||
}
|
||||
|
||||
ChromeDebuggerActor.prototype = Object.create(ThreadActor.prototype);
|
||||
@ -4857,38 +4752,7 @@ update(ChromeDebuggerActor.prototype, {
|
||||
* Override the eligibility check for scripts and sources to make sure every
|
||||
* script and source with a URL is stored when debugging chrome.
|
||||
*/
|
||||
_allowSource: function(aSourceURL) !!aSourceURL,
|
||||
|
||||
/**
|
||||
* An object that will be used by ThreadActors to tailor their behavior
|
||||
* depending on the debugging context being required (chrome or content).
|
||||
* The methods that this object provides must be bound to the ThreadActor
|
||||
* before use.
|
||||
*/
|
||||
globalManager: {
|
||||
findGlobals: function () {
|
||||
// Add every global known to the debugger as debuggee.
|
||||
this.dbg.addAllGlobalsAsDebuggees();
|
||||
},
|
||||
|
||||
/**
|
||||
* A function that the engine calls when a new global object has been
|
||||
* created.
|
||||
*
|
||||
* @param aGlobal Debugger.Object
|
||||
* The new global object that was created.
|
||||
*/
|
||||
onNewGlobal: function (aGlobal) {
|
||||
this.addDebuggee(aGlobal);
|
||||
// Notify the client.
|
||||
this.conn.send({
|
||||
from: this.actorID,
|
||||
type: "newGlobal",
|
||||
// TODO: after bug 801084 lands see if we need to JSONify this.
|
||||
hostAnnotations: aGlobal.hostAnnotations
|
||||
});
|
||||
}
|
||||
}
|
||||
_allowSource: aSourceURL => !!aSourceURL
|
||||
});
|
||||
|
||||
exports.ChromeDebuggerActor = ChromeDebuggerActor;
|
||||
@ -4902,18 +4766,12 @@ exports.ChromeDebuggerActor = ChromeDebuggerActor;
|
||||
* is associated. (Currently unused, but required to make this
|
||||
* constructor usable with addGlobalActor.)
|
||||
*
|
||||
* @param aHooks object
|
||||
* An object with preNest and postNest methods for calling
|
||||
* when entering and exiting a nested event loops.
|
||||
*
|
||||
* @param aAddonID string
|
||||
* ID of the add-on this actor will debug. It will be used to
|
||||
* filter out globals marked for debugging.
|
||||
* @param aParent object
|
||||
* This actor's parent actor. See ThreadActor for a list of expected
|
||||
* properties.
|
||||
*/
|
||||
|
||||
function AddonThreadActor(aConnect, aHooks, aAddonID) {
|
||||
this.addonID = aAddonID;
|
||||
ThreadActor.call(this, aHooks);
|
||||
function AddonThreadActor(aConnect, aParent) {
|
||||
ThreadActor.call(this, aParent);
|
||||
}
|
||||
|
||||
AddonThreadActor.prototype = Object.create(ThreadActor.prototype);
|
||||
@ -4935,7 +4793,7 @@ update(AddonThreadActor.prototype, {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XPIProvider.jsm evals some code in every add-on's bootstrap.js. Hide it
|
||||
// XPIProvider.jsm evals some code in every add-on's bootstrap.js. Hide it.
|
||||
if (aSourceURL == "resource://gre/modules/addons/XPIProvider.jsm") {
|
||||
return false;
|
||||
}
|
||||
@ -4943,97 +4801,6 @@ update(AddonThreadActor.prototype, {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* An object that will be used by ThreadActors to tailor their
|
||||
* behaviour depending on the debugging context being required (chrome,
|
||||
* addon or content). The methods that this object provides must
|
||||
* be bound to the ThreadActor before use.
|
||||
*/
|
||||
globalManager: {
|
||||
findGlobals: function ADA_findGlobals() {
|
||||
for (let global of this.dbg.findAllGlobals()) {
|
||||
if (this._checkGlobal(global)) {
|
||||
this.dbg.addDebuggee(global);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* A function that the engine calls when a new global object
|
||||
* has been created.
|
||||
*
|
||||
* @param aGlobal Debugger.Object
|
||||
* The new global object that was created.
|
||||
*/
|
||||
onNewGlobal: function ADA_onNewGlobal(aGlobal) {
|
||||
if (this._checkGlobal(aGlobal)) {
|
||||
this.addDebuggee(aGlobal);
|
||||
// Notify the client.
|
||||
this.conn.send({
|
||||
from: this.actorID,
|
||||
type: "newGlobal",
|
||||
// TODO: after bug 801084 lands see if we need to JSONify this.
|
||||
hostAnnotations: aGlobal.hostAnnotations
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the provided global belongs to the debugged add-on.
|
||||
*
|
||||
* @param aGlobal Debugger.Object
|
||||
*/
|
||||
_checkGlobal: function ADA_checkGlobal(aGlobal) {
|
||||
let obj = null;
|
||||
try {
|
||||
obj = aGlobal.unsafeDereference();
|
||||
}
|
||||
catch (e) {
|
||||
// Because of bug 991399 we sometimes get bad objects here. If we can't
|
||||
// dereference them then they won't be useful to us
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// This will fail for non-Sandbox objects, hence the try-catch block.
|
||||
let metadata = Cu.getSandboxMetadata(obj);
|
||||
if (metadata) {
|
||||
return metadata.addonID === this.addonID;
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
if (obj instanceof Ci.nsIDOMWindow) {
|
||||
let id = {};
|
||||
if (mapURIToAddonID(obj.document.documentURIObject, id)) {
|
||||
return id.value === this.addonID;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the global for a __URI__ property and then try to map that to an
|
||||
// add-on
|
||||
let uridescriptor = aGlobal.getOwnPropertyDescriptor("__URI__");
|
||||
if (uridescriptor && "value" in uridescriptor && uridescriptor.value) {
|
||||
let uri;
|
||||
try {
|
||||
uri = Services.io.newURI(uridescriptor.value, null, null);
|
||||
}
|
||||
catch (e) {
|
||||
DevToolsUtils.reportException("AddonThreadActor.prototype._checkGlobal",
|
||||
new Error("Invalid URI: " + uridescriptor.value));
|
||||
return false;
|
||||
}
|
||||
|
||||
let id = {};
|
||||
if (mapURIToAddonID(uri, id)) {
|
||||
return id.value === this.addonID;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
exports.AddonThreadActor = AddonThreadActor;
|
||||
|
@ -67,15 +67,20 @@ const TRACE_TYPES = new Set([
|
||||
]);
|
||||
|
||||
/**
|
||||
* Creates a TraceActor. TraceActor provides a stream of function
|
||||
* Creates a TracerActor. TracerActor provides a stream of function
|
||||
* call/return packets to a remote client gathering a full trace.
|
||||
*/
|
||||
function TraceActor(aConn, aParentActor)
|
||||
function TracerActor(aConn, aParent)
|
||||
{
|
||||
this._dbg = null;
|
||||
this._parent = aParent;
|
||||
this._attached = false;
|
||||
this._activeTraces = new MapStack();
|
||||
this._totalTraces = 0;
|
||||
this._startTime = 0;
|
||||
this._sequence = 0;
|
||||
this._bufferSendTimer = null;
|
||||
this._buffer = [];
|
||||
|
||||
// Keep track of how many different trace requests have requested what kind of
|
||||
// tracing info. This way we can minimize the amount of data we are collecting
|
||||
@ -85,27 +90,25 @@ function TraceActor(aConn, aParentActor)
|
||||
this._requestsForTraceType[type] = 0;
|
||||
}
|
||||
|
||||
this._sequence = 0;
|
||||
this._bufferSendTimer = null;
|
||||
this._buffer = [];
|
||||
this.onEnterFrame = this.onEnterFrame.bind(this);
|
||||
this.onExitFrame = this.onExitFrame.bind(this);
|
||||
|
||||
// aParentActor.window might be an Xray for a window, but it might also be a
|
||||
// double-wrapper for a Sandbox. We want to unwrap the latter but not the
|
||||
// former.
|
||||
this.global = aParentActor.window;
|
||||
if (!Cu.isXrayWrapper(this.global)) {
|
||||
this.global = this.global.wrappedJSObject;
|
||||
}
|
||||
}
|
||||
|
||||
TraceActor.prototype = {
|
||||
TracerActor.prototype = {
|
||||
actorPrefix: "trace",
|
||||
|
||||
get attached() { return this._attached; },
|
||||
get idle() { return this._attached && this._activeTraces.size === 0; },
|
||||
get tracing() { return this._attached && this._activeTraces.size > 0; },
|
||||
|
||||
get dbg() {
|
||||
if (!this._dbg) {
|
||||
this._dbg = this._parent.makeDebugger();
|
||||
this._dbg.onEnterFrame = this.onEnterFrame;
|
||||
}
|
||||
return this._dbg;
|
||||
},
|
||||
|
||||
/**
|
||||
* Buffer traces and only send them every BUFFER_SEND_DELAY milliseconds.
|
||||
*/
|
||||
@ -123,74 +126,6 @@ TraceActor.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes a Debugger instance and adds listeners to it.
|
||||
*/
|
||||
_initDebugger: function() {
|
||||
this.dbg = new Debugger();
|
||||
this.dbg.onEnterFrame = this.onEnterFrame.bind(this);
|
||||
this.dbg.onNewGlobalObject = this.globalManager.onNewGlobal.bind(this);
|
||||
this.dbg.enabled = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a debuggee global to the Debugger object.
|
||||
*/
|
||||
_addDebuggee: function(aGlobal) {
|
||||
try {
|
||||
this.dbg.addDebuggee(aGlobal);
|
||||
} catch (e) {
|
||||
// Ignore attempts to add the debugger's compartment as a debuggee.
|
||||
DevToolsUtils.reportException("TraceActor",
|
||||
new Error("Ignoring request to add the debugger's "
|
||||
+ "compartment as a debuggee"));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the provided window and all windows in its frame tree as debuggees.
|
||||
*/
|
||||
_addDebuggees: function(aWindow) {
|
||||
this._addDebuggee(aWindow);
|
||||
let frames = aWindow.frames;
|
||||
if (frames) {
|
||||
for (let i = 0; i < frames.length; i++) {
|
||||
this._addDebuggees(frames[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* An object used by TraceActors to tailor their behavior depending
|
||||
* on the debugging context required (chrome or content).
|
||||
*/
|
||||
globalManager: {
|
||||
/**
|
||||
* Adds all globals in the global object as debuggees.
|
||||
*/
|
||||
findGlobals: function() {
|
||||
this._addDebuggees(this.global);
|
||||
},
|
||||
|
||||
/**
|
||||
* A function that the engine calls when a new global object has been
|
||||
* created. Adds the global object as a debuggee if it is in the content
|
||||
* window.
|
||||
*
|
||||
* @param aGlobal Debugger.Object
|
||||
* The new global object that was created.
|
||||
*/
|
||||
onNewGlobal: function(aGlobal) {
|
||||
// Content debugging only cares about new globals in the content
|
||||
// window, like iframe children.
|
||||
if (aGlobal.hostAnnotations &&
|
||||
aGlobal.hostAnnotations.type == "document" &&
|
||||
aGlobal.hostAnnotations.element === this.global) {
|
||||
this._addDebuggee(aGlobal);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a protocol request to attach to the trace actor.
|
||||
*
|
||||
@ -205,11 +140,7 @@ TraceActor.prototype = {
|
||||
};
|
||||
}
|
||||
|
||||
if (!this.dbg) {
|
||||
this._initDebugger();
|
||||
this.globalManager.findGlobals.call(this);
|
||||
}
|
||||
|
||||
this.dbg.addDebuggees();
|
||||
this._attached = true;
|
||||
|
||||
return {
|
||||
@ -230,10 +161,12 @@ TraceActor.prototype = {
|
||||
this.onStopTrace();
|
||||
}
|
||||
|
||||
this.dbg = null;
|
||||
|
||||
this._dbg = null;
|
||||
this._attached = false;
|
||||
return { type: "detached" };
|
||||
|
||||
return {
|
||||
type: "detached"
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
@ -307,7 +240,11 @@ TraceActor.prototype = {
|
||||
this.dbg.enabled = false;
|
||||
}
|
||||
|
||||
return { type: "stoppedTrace", why: "requested", name: name };
|
||||
return {
|
||||
type: "stoppedTrace",
|
||||
why: "requested",
|
||||
name
|
||||
};
|
||||
},
|
||||
|
||||
// JS Debugger API hooks.
|
||||
@ -443,19 +380,19 @@ TraceActor.prototype = {
|
||||
/**
|
||||
* The request types this actor can handle.
|
||||
*/
|
||||
TraceActor.prototype.requestTypes = {
|
||||
"attach": TraceActor.prototype.onAttach,
|
||||
"detach": TraceActor.prototype.onDetach,
|
||||
"startTrace": TraceActor.prototype.onStartTrace,
|
||||
"stopTrace": TraceActor.prototype.onStopTrace
|
||||
TracerActor.prototype.requestTypes = {
|
||||
"attach": TracerActor.prototype.onAttach,
|
||||
"detach": TracerActor.prototype.onDetach,
|
||||
"startTrace": TracerActor.prototype.onStartTrace,
|
||||
"stopTrace": TracerActor.prototype.onStopTrace
|
||||
};
|
||||
|
||||
exports.register = function(handle) {
|
||||
handle.addTabActor(TraceActor, "traceActor");
|
||||
handle.addTabActor(TracerActor, "traceActor");
|
||||
};
|
||||
|
||||
exports.unregister = function(handle) {
|
||||
handle.removeTabActor(TraceActor, "traceActor");
|
||||
handle.removeTabActor(TracerActor, "traceActor");
|
||||
};
|
||||
|
||||
|
||||
@ -610,7 +547,7 @@ function createValueSnapshot(aValue, aDetailed=false) {
|
||||
? detailedObjectSnapshot(aValue)
|
||||
: objectSnapshot(aValue);
|
||||
default:
|
||||
DevToolsUtils.reportException("TraceActor",
|
||||
DevToolsUtils.reportException("TracerActor",
|
||||
new Error("Failed to provide a grip for: " + aValue));
|
||||
return null;
|
||||
}
|
||||
|
100
toolkit/devtools/server/actors/utils/make-debugger.js
Normal file
100
toolkit/devtools/server/actors/utils/make-debugger.js
Normal file
@ -0,0 +1,100 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const Debugger = require("Debugger");
|
||||
|
||||
const { reportException } = require("devtools/toolkit/DevToolsUtils");
|
||||
|
||||
/**
|
||||
* Multiple actors that use a |Debugger| instance come in a few versions, each
|
||||
* with a different set of debuggees. One version for content tabs (globals
|
||||
* within a tab), one version for chrome debugging (all globals), and sometimes
|
||||
* a third version for addon debugging (chrome globals the addon is loaded in
|
||||
* and content globals the addon injects scripts into). The |makeDebugger|
|
||||
* function helps us avoid repeating the logic for finding and maintaining the
|
||||
* correct set of globals for a given |Debugger| instance across each version of
|
||||
* all of our actors.
|
||||
*
|
||||
* The |makeDebugger| function expects a single object parameter with the
|
||||
* following properties:
|
||||
*
|
||||
* @param Function findDebuggees
|
||||
* Called with one argument: a |Debugger| instance. This function should
|
||||
* return an iterable of globals to be added to the |Debugger|
|
||||
* instance. The globals may be wrapped in a |Debugger.Object|, or
|
||||
* unwrapped.
|
||||
*
|
||||
* @param Function shouldAddNewGlobalAsDebuggee
|
||||
* Called with one argument: a |Debugger.Object| wrapping a global
|
||||
* object. This function must return |true| if the global object should
|
||||
* be added as debuggee, and |false| otherwise.
|
||||
*
|
||||
* @returns Debugger
|
||||
* Returns a |Debugger| instance that can manage its set of debuggee
|
||||
* globals itself and is decorated with the |EventEmitter| class.
|
||||
*
|
||||
* Events emitted by the returned |Debugger| instance:
|
||||
*
|
||||
* - "newGlobal": Emitted when a new global has been added as a
|
||||
* debuggee. Passes the |Debugger.Object| wrapping the new
|
||||
* debuggee global to listeners.
|
||||
*
|
||||
* Existing |Debugger| properties set on the returned |Debugger|
|
||||
* instance:
|
||||
*
|
||||
* - onNewGlobalObject: The |Debugger| will automatically add new
|
||||
* globals as debuggees if calling |shouldAddNewGlobalAsDebuggee|
|
||||
* with the global returns true.
|
||||
*
|
||||
* - uncaughtExceptionHook: The |Debugger| already has an error
|
||||
* reporter attached to |uncaughtExceptionHook|, so if any
|
||||
* |Debugger| hooks fail, the error will be reported.
|
||||
*
|
||||
* New properties set on the returned |Debugger| instance:
|
||||
*
|
||||
* - addDebuggees: A function which takes no arguments. It adds all
|
||||
* current globals that should be debuggees (as determined by
|
||||
* |findDebuggees|) to the |Debugger| instance.
|
||||
*/
|
||||
module.exports = function makeDebugger({ findDebuggees, shouldAddNewGlobalAsDebuggee }) {
|
||||
const dbg = new Debugger();
|
||||
EventEmitter.decorate(dbg);
|
||||
|
||||
dbg.uncaughtExceptionHook = reportDebuggerHookException;
|
||||
|
||||
dbg.onNewGlobalObject = global => {
|
||||
if (shouldAddNewGlobalAsDebuggee(global)) {
|
||||
safeAddDebuggee(dbg, global);
|
||||
}
|
||||
};
|
||||
|
||||
dbg.addDebuggees = () => {
|
||||
for (let global of findDebuggees(dbg)) {
|
||||
safeAddDebuggee(dbg, global);
|
||||
}
|
||||
};
|
||||
|
||||
return dbg;
|
||||
};
|
||||
|
||||
const reportDebuggerHookException = e => reportException("Debugger Hook", e);
|
||||
|
||||
/**
|
||||
* Add |global| as a debuggee to |dbg|, handling error cases.
|
||||
*/
|
||||
function safeAddDebuggee(dbg, global) {
|
||||
try {
|
||||
let wrappedGlobal = dbg.addDebuggee(global);
|
||||
if (wrappedGlobal) {
|
||||
dbg.emit("newGlobal", wrappedGlobal);
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignoring attempt to add the debugger's compartment as a debuggee.
|
||||
}
|
||||
}
|
47
toolkit/devtools/server/actors/utils/map-uri-to-addon-id.js
Normal file
47
toolkit/devtools/server/actors/utils/map-uri-to-addon-id.js
Normal file
@ -0,0 +1,47 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
const Services = require("Services");
|
||||
const { Cc, Ci } = require("chrome");
|
||||
|
||||
Object.defineProperty(this, "addonManager", {
|
||||
get: (function () {
|
||||
let cached;
|
||||
return () => cached
|
||||
? cached
|
||||
: (cached = Cc["@mozilla.org/addons/integration;1"]
|
||||
.getService(Ci.amIAddonManager))
|
||||
}())
|
||||
});
|
||||
|
||||
const B2G_ID = "{3c2e2abc-06d4-11e1-ac3b-374f68613e61}";
|
||||
|
||||
/**
|
||||
* This is a wrapper around amIAddonManager.mapURIToAddonID which always returns
|
||||
* false on B2G to avoid loading the add-on manager there and reports any
|
||||
* exceptions rather than throwing so that the caller doesn't have to worry
|
||||
* about them.
|
||||
*/
|
||||
module.exports = function mapURIToAddonID(uri, id) {
|
||||
if (!Services.appinfo
|
||||
|| Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT
|
||||
|| Services.appinfo.ID == B2G_ID
|
||||
|| !uri
|
||||
|| !addonManager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return addonManager.mapURIToAddonID(uri, id);
|
||||
}
|
||||
catch (e) {
|
||||
DevToolsUtils.reportException("mapURIToAddonID", e);
|
||||
return false;
|
||||
}
|
||||
};
|
@ -14,6 +14,8 @@ let { AddonThreadActor, ThreadActor } = require("devtools/server/actors/script")
|
||||
let { DebuggerServer } = require("devtools/server/main");
|
||||
let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
let { dbg_assert } = DevToolsUtils;
|
||||
let makeDebugger = require("./utils/make-debugger");
|
||||
let mapURIToAddonID = require("./utils/map-uri-to-addon-id");
|
||||
|
||||
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
@ -71,6 +73,29 @@ function sendShutdownEvent() {
|
||||
|
||||
exports.sendShutdownEvent = sendShutdownEvent;
|
||||
|
||||
/**
|
||||
* Unwrap a global that is wrapped in a |Debugger.Object|, or if the global has
|
||||
* become a dead object, return |undefined|.
|
||||
*
|
||||
* @param Debugger.Object wrappedGlobal
|
||||
* The |Debugger.Object| which wraps a global.
|
||||
*
|
||||
* @returns {Object|undefined}
|
||||
* Returns the unwrapped global object or |undefined| if unwrapping
|
||||
* failed.
|
||||
*/
|
||||
const unwrapDebuggerObjectGlobal = wrappedGlobal => {
|
||||
let global;
|
||||
try {
|
||||
global = wrappedGlobal.unsafeDereference();
|
||||
}
|
||||
catch (e) {
|
||||
// Because of bug 991399 we sometimes get bad objects here. If we
|
||||
// can't dereference them then they won't be useful to us.
|
||||
}
|
||||
return global;
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a root actor appropriate for use in a server running in a
|
||||
* browser. The returned root actor:
|
||||
@ -520,6 +545,13 @@ function TabActor(aConnection)
|
||||
this._extraActors = {};
|
||||
this._exited = false;
|
||||
|
||||
this._shouldAddNewGlobalAsDebuggee = this._shouldAddNewGlobalAsDebuggee.bind(this);
|
||||
|
||||
this.makeDebugger = makeDebugger.bind(null, {
|
||||
findDebuggees: () => this.windows,
|
||||
shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
|
||||
});
|
||||
|
||||
this.traits = { reconfigure: true };
|
||||
}
|
||||
|
||||
@ -715,6 +747,37 @@ TabActor.prototype = {
|
||||
this._exited = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return true if the given global is associated with this tab and should be
|
||||
* added as a debuggee, false otherwise.
|
||||
*/
|
||||
_shouldAddNewGlobalAsDebuggee: function (wrappedGlobal) {
|
||||
if (wrappedGlobal.hostAnnotations &&
|
||||
wrappedGlobal.hostAnnotations.type == "document" &&
|
||||
wrappedGlobal.hostAnnotations.element === this.window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let global = unwrapDebuggerObjectGlobal(wrappedGlobal);
|
||||
if (!global) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the global is a sdk page-mod sandbox.
|
||||
let metadata = {};
|
||||
let id = "";
|
||||
try {
|
||||
id = getInnerId(this.window);
|
||||
metadata = Cu.getSandboxMetadata(global);
|
||||
}
|
||||
catch (e) {}
|
||||
if (metadata["inner-window-id"] && metadata["inner-window-id"] == id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/* Support for DebuggerServer.addTabActor. */
|
||||
_createExtraActors: createExtraActors,
|
||||
_appendExtraActors: appendExtraActors,
|
||||
@ -999,7 +1062,7 @@ TabActor.prototype = {
|
||||
// Refresh the debuggee list when a new window object appears (top window or
|
||||
// iframe).
|
||||
if (threadActor.attached) {
|
||||
threadActor.findGlobals();
|
||||
threadActor.dbg.addDebuggees();
|
||||
}
|
||||
},
|
||||
|
||||
@ -1287,6 +1350,14 @@ function BrowserAddonActor(aConnection, aAddon) {
|
||||
this.conn.addActorPool(this._contextPool);
|
||||
this._threadActor = null;
|
||||
this._global = null;
|
||||
|
||||
this._shouldAddNewGlobalAsDebuggee = this._shouldAddNewGlobalAsDebuggee.bind(this);
|
||||
|
||||
this.makeDebugger = makeDebugger.bind(null, {
|
||||
findDebuggees: this._findDebuggees.bind(this),
|
||||
shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
|
||||
});
|
||||
|
||||
AddonManager.addAddonListener(this);
|
||||
}
|
||||
|
||||
@ -1373,8 +1444,7 @@ BrowserAddonActor.prototype = {
|
||||
}
|
||||
|
||||
if (!this.attached) {
|
||||
this._threadActor = new AddonThreadActor(this.conn, this,
|
||||
this._addon.id);
|
||||
this._threadActor = new AddonThreadActor(this.conn, this);
|
||||
this._contextPool.addActor(this._threadActor);
|
||||
}
|
||||
|
||||
@ -1413,6 +1483,61 @@ BrowserAddonActor.prototype = {
|
||||
windowUtils.resumeTimeouts();
|
||||
windowUtils.suppressEventHandling(false);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return true if the given global is associated with this addon and should be
|
||||
* added as a debuggee, false otherwise.
|
||||
*/
|
||||
_shouldAddNewGlobalAsDebuggee: function (aGlobal) {
|
||||
const global = unwrapDebuggerObjectGlobal(aGlobal);
|
||||
try {
|
||||
// This will fail for non-Sandbox objects, hence the try-catch block.
|
||||
let metadata = Cu.getSandboxMetadata(global);
|
||||
if (metadata) {
|
||||
return metadata.addonID === this.id;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (global instanceof Ci.nsIDOMWindow) {
|
||||
let id = {};
|
||||
if (mapURIToAddonID(global.document.documentURIObject, id)) {
|
||||
return id.value === this.id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the global for a __URI__ property and then try to map that to an
|
||||
// add-on
|
||||
let uridescriptor = aGlobal.getOwnPropertyDescriptor("__URI__");
|
||||
if (uridescriptor && "value" in uridescriptor && uridescriptor.value) {
|
||||
let uri;
|
||||
try {
|
||||
uri = Services.io.newURI(uridescriptor.value, null, null);
|
||||
}
|
||||
catch (e) {
|
||||
DevToolsUtils.reportException(
|
||||
"BrowserAddonActor.prototype._shouldAddNewGlobalAsDebuggee",
|
||||
new Error("Invalid URI: " + uridescriptor.value)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
let id = {};
|
||||
if (mapURIToAddonID(uri, id)) {
|
||||
return id.value === this.id;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Yield the current set of globals associated with this addon that should be
|
||||
* added as debuggees.
|
||||
*/
|
||||
_findDebuggees: function (dbg) {
|
||||
return dbg.findAllGlobals().filter(this._shouldAddNewGlobalAsDebuggee);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -10,7 +10,6 @@ const { Cc, Ci, Cu } = require("chrome");
|
||||
const { DebuggerServer, ActorPool } = require("devtools/server/main");
|
||||
const { EnvironmentActor, LongStringActor, ObjectActor, ThreadActor } = require("devtools/server/actors/script");
|
||||
const { update } = require("devtools/toolkit/DevToolsUtils");
|
||||
const Debugger = require("Debugger");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
@ -67,7 +66,7 @@ function WebConsoleActor(aConnection, aParentActor)
|
||||
|
||||
this._prefs = {};
|
||||
|
||||
this.dbg = new Debugger();
|
||||
this.dbg = this.parentActor.makeDebugger();
|
||||
|
||||
this._netEvents = new Map();
|
||||
this._gripDepth = 0;
|
||||
@ -1011,7 +1010,6 @@ WebConsoleActor.prototype =
|
||||
// If we have an object to bind to |_self|, create a Debugger.Object
|
||||
// referring to that object, belonging to dbg.
|
||||
let bindSelf = null;
|
||||
let dbgWindow = dbg.makeGlobalObjectReference(this.evalWindow);
|
||||
if (aOptions.bindObjectActor) {
|
||||
let objActor = this.getActorByID(aOptions.bindObjectActor);
|
||||
if (objActor) {
|
||||
|
@ -99,7 +99,8 @@ let listener = {
|
||||
}
|
||||
|
||||
// Make sure we exit all nested event loops so that the test can finish.
|
||||
while (DebuggerServer.xpcInspector.eventLoopNestLevel > 0) {
|
||||
while (DebuggerServer.xpcInspector
|
||||
&& DebuggerServer.xpcInspector.eventLoopNestLevel > 0) {
|
||||
DebuggerServer.xpcInspector.exitNestedEventLoop();
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,9 @@ function test_enter_exit_frame()
|
||||
do_check_eq(traceNames[4], "foo",
|
||||
'Should have entered "foo" frame in fifth packet');
|
||||
finishClient(gClient);
|
||||
});
|
||||
})
|
||||
.then(null, e => DevToolsUtils.reportException("test_trace_actor-04.js",
|
||||
e));
|
||||
}
|
||||
|
||||
function start_trace()
|
||||
|
@ -6,6 +6,7 @@ const { RootActor } = require("devtools/server/actors/root");
|
||||
const { ThreadActor } = require("devtools/server/actors/script");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const promise = require("promise");
|
||||
const makeDebugger = require("devtools/server/actors/utils/make-debugger");
|
||||
|
||||
var gTestGlobals = [];
|
||||
DebuggerServer.addTestGlobal = function(aGlobal) {
|
||||
@ -66,6 +67,13 @@ function TestTabActor(aConnection, aGlobal)
|
||||
this.conn.addActor(this._threadActor);
|
||||
this._attached = false;
|
||||
this._extraActors = {};
|
||||
this.makeDebugger = makeDebugger.bind(null, {
|
||||
findDebuggees: () => [this._global],
|
||||
shouldAddNewGlobalAsDebuggee: g => g.hostAnnotations &&
|
||||
g.hostAnnotations.type == "document" &&
|
||||
g.hostAnnotations.element === this._global
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
TestTabActor.prototype = {
|
||||
|
Loading…
Reference in New Issue
Block a user