mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1435187 - Refactor the script actor. r=jdescottes
- Extract paused scoped objects. - Extract event loop stack. r=jdescottes - Extract actor stores. r=jdescottes - Move script.js to actor.js. r=jdescottes --HG-- rename : devtools/server/actors/script.js => devtools/server/actors/thread.js
This commit is contained in:
parent
1f140ec503
commit
f805944739
@ -13,8 +13,8 @@ var { ConsoleAPIListener } = require("devtools/server/actors/webconsole/listener
|
||||
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
var { assert, update } = DevToolsUtils;
|
||||
|
||||
loader.lazyRequireGetter(this, "AddonThreadActor", "devtools/server/actors/script", true);
|
||||
loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/script", true);
|
||||
loader.lazyRequireGetter(this, "AddonThreadActor", "devtools/server/actors/thread", true);
|
||||
loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/thread", true);
|
||||
loader.lazyRequireGetter(this, "mapURIToAddonID", "devtools/server/actors/utils/map-uri-to-addon-id");
|
||||
loader.lazyRequireGetter(this, "WebConsoleActor", "devtools/server/actors/webconsole", true);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const Services = require("Services");
|
||||
|
||||
const { ChromeDebuggerActor } = require("devtools/server/actors/script");
|
||||
const { ChromeDebuggerActor } = require("devtools/server/actors/thread");
|
||||
const { WebConsoleActor } = require("devtools/server/actors/webconsole");
|
||||
const makeDebugger = require("devtools/server/actors/utils/make-debugger");
|
||||
const { ActorPool } = require("devtools/server/main");
|
||||
|
@ -42,6 +42,7 @@ DevToolsModules(
|
||||
'memory.js',
|
||||
'monitor.js',
|
||||
'object.js',
|
||||
'pause-scoped.js',
|
||||
'perf.js',
|
||||
'performance-recording.js',
|
||||
'performance.js',
|
||||
@ -51,13 +52,13 @@ DevToolsModules(
|
||||
'promises.js',
|
||||
'reflow.js',
|
||||
'root.js',
|
||||
'script.js',
|
||||
'source.js',
|
||||
'storage.js',
|
||||
'string.js',
|
||||
'styles.js',
|
||||
'stylesheets.js',
|
||||
'tab.js',
|
||||
'thread.js',
|
||||
'timeline.js',
|
||||
'webaudio.js',
|
||||
'webbrowser.js',
|
||||
|
128
devtools/server/actors/pause-scoped.js
Normal file
128
devtools/server/actors/pause-scoped.js
Normal file
@ -0,0 +1,128 @@
|
||||
/* -*- 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 { ObjectActor } = require("devtools/server/actors/object");
|
||||
|
||||
/**
|
||||
* A base actor for any actors that should only respond receive messages in the
|
||||
* paused state. Subclasses may expose a `threadActor` which is used to help
|
||||
* determine when we are in a paused state. Subclasses should set their own
|
||||
* "constructor" property if they want better error messages. You should never
|
||||
* instantiate a PauseScopedActor directly, only through subclasses.
|
||||
*/
|
||||
function PauseScopedActor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A function decorator for creating methods to handle protocol messages that
|
||||
* should only be received while in the paused state.
|
||||
*
|
||||
* @param method Function
|
||||
* The function we are decorating.
|
||||
*/
|
||||
PauseScopedActor.withPaused = function (method) {
|
||||
return function () {
|
||||
if (this.isPaused()) {
|
||||
return method.apply(this, arguments);
|
||||
}
|
||||
return this._wrongState();
|
||||
};
|
||||
};
|
||||
|
||||
PauseScopedActor.prototype = {
|
||||
|
||||
/**
|
||||
* Returns true if we are in the paused state.
|
||||
*/
|
||||
isPaused: function () {
|
||||
// When there is not a ThreadActor available (like in the webconsole) we
|
||||
// have to be optimistic and assume that we are paused so that we can
|
||||
// respond to requests.
|
||||
return this.threadActor ? this.threadActor.state === "paused" : true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the wrongState response packet for this actor.
|
||||
*/
|
||||
_wrongState: function () {
|
||||
return {
|
||||
error: "wrongState",
|
||||
message: this.constructor.name +
|
||||
" actors can only be accessed while the thread is paused."
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a pause-scoped actor for the specified object.
|
||||
* @see ObjectActor
|
||||
*/
|
||||
function PauseScopedObjectActor(obj, hooks) {
|
||||
ObjectActor.call(this, obj, hooks);
|
||||
this.hooks.promote = hooks.promote;
|
||||
this.hooks.isThreadLifetimePool = hooks.isThreadLifetimePool;
|
||||
}
|
||||
|
||||
PauseScopedObjectActor.prototype = Object.create(PauseScopedActor.prototype);
|
||||
|
||||
Object.assign(PauseScopedObjectActor.prototype, ObjectActor.prototype);
|
||||
|
||||
Object.assign(PauseScopedObjectActor.prototype, {
|
||||
constructor: PauseScopedObjectActor,
|
||||
actorPrefix: "pausedobj",
|
||||
|
||||
onOwnPropertyNames:
|
||||
PauseScopedActor.withPaused(ObjectActor.prototype.onOwnPropertyNames),
|
||||
|
||||
onPrototypeAndProperties:
|
||||
PauseScopedActor.withPaused(ObjectActor.prototype.onPrototypeAndProperties),
|
||||
|
||||
onPrototype: PauseScopedActor.withPaused(ObjectActor.prototype.onPrototype),
|
||||
onProperty: PauseScopedActor.withPaused(ObjectActor.prototype.onProperty),
|
||||
onDecompile: PauseScopedActor.withPaused(ObjectActor.prototype.onDecompile),
|
||||
|
||||
onDisplayString:
|
||||
PauseScopedActor.withPaused(ObjectActor.prototype.onDisplayString),
|
||||
|
||||
onParameterNames:
|
||||
PauseScopedActor.withPaused(ObjectActor.prototype.onParameterNames),
|
||||
|
||||
/**
|
||||
* Handle a protocol request to promote a pause-lifetime grip to a
|
||||
* thread-lifetime grip.
|
||||
*
|
||||
* @param request object
|
||||
* The protocol request object.
|
||||
*/
|
||||
onThreadGrip: PauseScopedActor.withPaused(function (request) {
|
||||
this.hooks.promote();
|
||||
return {};
|
||||
}),
|
||||
|
||||
/**
|
||||
* Handle a protocol request to release a thread-lifetime grip.
|
||||
*
|
||||
* @param request object
|
||||
* The protocol request object.
|
||||
*/
|
||||
onRelease: PauseScopedActor.withPaused(function (request) {
|
||||
if (this.hooks.isThreadLifetimePool()) {
|
||||
return { error: "notReleasable",
|
||||
message: "Only thread-lifetime actors can be released." };
|
||||
}
|
||||
|
||||
this.release();
|
||||
return {};
|
||||
}),
|
||||
});
|
||||
|
||||
Object.assign(PauseScopedObjectActor.prototype.requestTypes, {
|
||||
"threadGrip": PauseScopedObjectActor.prototype.onThreadGrip,
|
||||
});
|
||||
|
||||
exports.PauseScopedObjectActor = PauseScopedObjectActor;
|
@ -27,8 +27,8 @@ const EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
const EXTENSION_CONTENT_JSM = "resource://gre/modules/ExtensionContent.jsm";
|
||||
|
||||
loader.lazyRequireGetter(this, "ThreadActor", "devtools/server/actors/script", true);
|
||||
loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/script", true);
|
||||
loader.lazyRequireGetter(this, "ThreadActor", "devtools/server/actors/thread", true);
|
||||
loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/thread", true);
|
||||
loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker-list", true);
|
||||
loader.lazyImporter(this, "ExtensionContent", EXTENSION_CONTENT_JSM);
|
||||
|
||||
|
@ -8,14 +8,13 @@
|
||||
|
||||
const Services = require("Services");
|
||||
const { Cc, Ci, Cr } = require("chrome");
|
||||
const { ActorPool, OriginalLocation, GeneratedLocation } = require("devtools/server/actors/common");
|
||||
const { ObjectActor, createValueGrip, longStringGrip } = require("devtools/server/actors/object");
|
||||
const { ActorPool, GeneratedLocation } = require("devtools/server/actors/common");
|
||||
const { createValueGrip, longStringGrip } = require("devtools/server/actors/object");
|
||||
const { ActorClassWithSpec } = require("devtools/shared/protocol");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const flags = require("devtools/shared/flags");
|
||||
const { assert, dumpn } = DevToolsUtils;
|
||||
const promise = require("promise");
|
||||
const xpcInspector = require("xpcInspector");
|
||||
const { DevToolsWorker } = require("devtools/shared/worker/worker");
|
||||
const { threadSpec } = require("devtools/shared/specs/script");
|
||||
|
||||
@ -26,372 +25,17 @@ loader.lazyGetter(this, "Debugger", () => {
|
||||
hackDebugger(Debugger);
|
||||
return Debugger;
|
||||
});
|
||||
loader.lazyRequireGetter(this, "CssLogic", "devtools/server/css-logic", true);
|
||||
loader.lazyRequireGetter(this, "findCssSelector", "devtools/shared/inspector/css-logic", true);
|
||||
loader.lazyRequireGetter(this, "mapURIToAddonID", "devtools/server/actors/utils/map-uri-to-addon-id");
|
||||
loader.lazyRequireGetter(this, "BreakpointActor", "devtools/server/actors/breakpoint", true);
|
||||
loader.lazyRequireGetter(this, "setBreakpointAtEntryPoints", "devtools/server/actors/breakpoint", true);
|
||||
loader.lazyRequireGetter(this, "getSourceURL", "devtools/server/actors/source", true);
|
||||
loader.lazyRequireGetter(this, "EnvironmentActor", "devtools/server/actors/environment", true);
|
||||
loader.lazyRequireGetter(this, "SourceActorStore", "devtools/server/actors/utils/source-actor-store", true);
|
||||
loader.lazyRequireGetter(this, "BreakpointActorMap", "devtools/server/actors/utils/breakpoint-actor-map", true);
|
||||
loader.lazyRequireGetter(this, "PauseScopedObjectActor", "devtools/server/actors/pause-scoped", true);
|
||||
loader.lazyRequireGetter(this, "EventLoopStack", "devtools/server/actors/utils/event-loop", true);
|
||||
loader.lazyRequireGetter(this, "FrameActor", "devtools/server/actors/frame", true);
|
||||
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
||||
|
||||
/**
|
||||
* A BreakpointActorMap is a map from locations to instances of BreakpointActor.
|
||||
*/
|
||||
function BreakpointActorMap() {
|
||||
this._size = 0;
|
||||
this._actors = {};
|
||||
}
|
||||
|
||||
BreakpointActorMap.prototype = {
|
||||
/**
|
||||
* Return the number of BreakpointActors in this BreakpointActorMap.
|
||||
*
|
||||
* @returns Number
|
||||
* The number of BreakpointActor in this BreakpointActorMap.
|
||||
*/
|
||||
get size() {
|
||||
return this._size;
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate all BreakpointActors that match the given location in
|
||||
* this BreakpointActorMap.
|
||||
*
|
||||
* @param OriginalLocation location
|
||||
* The location for which matching BreakpointActors should be generated.
|
||||
*/
|
||||
findActors: function* (location = new OriginalLocation()) {
|
||||
// Fast shortcut for when we know we won't find any actors. Surprisingly
|
||||
// enough, this speeds up refreshing when there are no breakpoints set by
|
||||
// about 2x!
|
||||
if (this.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
function* findKeys(obj, key) {
|
||||
if (key !== undefined) {
|
||||
if (key in obj) {
|
||||
yield key;
|
||||
}
|
||||
} else {
|
||||
for (key of Object.keys(obj)) {
|
||||
yield key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let query = {
|
||||
sourceActorID: location.originalSourceActor
|
||||
? location.originalSourceActor.actorID
|
||||
: undefined,
|
||||
line: location.originalLine,
|
||||
};
|
||||
|
||||
// If location contains a line, assume we are searching for a whole line
|
||||
// breakpoint, and set begin/endColumn accordingly. Otherwise, we are
|
||||
// searching for all breakpoints, so begin/endColumn should be left unset.
|
||||
if (location.originalLine) {
|
||||
query.beginColumn = location.originalColumn ? location.originalColumn : 0;
|
||||
query.endColumn = location.originalColumn ? location.originalColumn + 1 : Infinity;
|
||||
} else {
|
||||
query.beginColumn = location.originalColumn ? query.originalColumn : undefined;
|
||||
query.endColumn = location.originalColumn ? query.originalColumn + 1 : undefined;
|
||||
}
|
||||
|
||||
for (let sourceActorID of findKeys(this._actors, query.sourceActorID)) {
|
||||
let actor = this._actors[sourceActorID];
|
||||
for (let line of findKeys(actor, query.line)) {
|
||||
for (let beginColumn of findKeys(actor[line], query.beginColumn)) {
|
||||
for (let endColumn of findKeys(actor[line][beginColumn],
|
||||
query.endColumn)) {
|
||||
yield actor[line][beginColumn][endColumn];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the BreakpointActor at the given location in this
|
||||
* BreakpointActorMap.
|
||||
*
|
||||
* @param OriginalLocation location
|
||||
* The location for which the BreakpointActor should be returned.
|
||||
*
|
||||
* @returns BreakpointActor actor
|
||||
* The BreakpointActor at the given location.
|
||||
*/
|
||||
getActor: function (originalLocation) {
|
||||
for (let actor of this.findActors(originalLocation)) {
|
||||
return actor;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the given BreakpointActor to the given location in this
|
||||
* BreakpointActorMap.
|
||||
*
|
||||
* @param OriginalLocation location
|
||||
* The location to which the given BreakpointActor should be set.
|
||||
*
|
||||
* @param BreakpointActor actor
|
||||
* The BreakpointActor to be set to the given location.
|
||||
*/
|
||||
setActor: function (location, actor) {
|
||||
let { originalSourceActor, originalLine, originalColumn } = location;
|
||||
|
||||
let sourceActorID = originalSourceActor.actorID;
|
||||
let line = originalLine;
|
||||
let beginColumn = originalColumn ? originalColumn : 0;
|
||||
let endColumn = originalColumn ? originalColumn + 1 : Infinity;
|
||||
|
||||
if (!this._actors[sourceActorID]) {
|
||||
this._actors[sourceActorID] = [];
|
||||
}
|
||||
if (!this._actors[sourceActorID][line]) {
|
||||
this._actors[sourceActorID][line] = [];
|
||||
}
|
||||
if (!this._actors[sourceActorID][line][beginColumn]) {
|
||||
this._actors[sourceActorID][line][beginColumn] = [];
|
||||
}
|
||||
if (!this._actors[sourceActorID][line][beginColumn][endColumn]) {
|
||||
++this._size;
|
||||
}
|
||||
this._actors[sourceActorID][line][beginColumn][endColumn] = actor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete the BreakpointActor from the given location in this
|
||||
* BreakpointActorMap.
|
||||
*
|
||||
* @param OriginalLocation location
|
||||
* The location from which the BreakpointActor should be deleted.
|
||||
*/
|
||||
deleteActor: function (location) {
|
||||
let { originalSourceActor, originalLine, originalColumn } = location;
|
||||
|
||||
let sourceActorID = originalSourceActor.actorID;
|
||||
let line = originalLine;
|
||||
let beginColumn = originalColumn ? originalColumn : 0;
|
||||
let endColumn = originalColumn ? originalColumn + 1 : Infinity;
|
||||
|
||||
if (this._actors[sourceActorID]) {
|
||||
if (this._actors[sourceActorID][line]) {
|
||||
if (this._actors[sourceActorID][line][beginColumn]) {
|
||||
if (this._actors[sourceActorID][line][beginColumn][endColumn]) {
|
||||
--this._size;
|
||||
}
|
||||
delete this._actors[sourceActorID][line][beginColumn][endColumn];
|
||||
if (Object.keys(this._actors[sourceActorID][line][beginColumn]).length === 0) {
|
||||
delete this._actors[sourceActorID][line][beginColumn];
|
||||
}
|
||||
}
|
||||
if (Object.keys(this._actors[sourceActorID][line]).length === 0) {
|
||||
delete this._actors[sourceActorID][line];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.BreakpointActorMap = BreakpointActorMap;
|
||||
|
||||
/**
|
||||
* Keeps track of persistent sources across reloads and ties different
|
||||
* source instances to the same actor id so that things like
|
||||
* breakpoints survive reloads. ThreadSources uses this to force the
|
||||
* same actorID on a SourceActor.
|
||||
*/
|
||||
function SourceActorStore() {
|
||||
// source identifier --> actor id
|
||||
this._sourceActorIds = Object.create(null);
|
||||
}
|
||||
|
||||
SourceActorStore.prototype = {
|
||||
/**
|
||||
* Lookup an existing actor id that represents this source, if available.
|
||||
*/
|
||||
getReusableActorId: function (source, originalUrl) {
|
||||
let url = this.getUniqueKey(source, originalUrl);
|
||||
if (url && url in this._sourceActorIds) {
|
||||
return this._sourceActorIds[url];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a source with an actorID.
|
||||
*/
|
||||
setReusableActorId: function (source, originalUrl, actorID) {
|
||||
let url = this.getUniqueKey(source, originalUrl);
|
||||
if (url) {
|
||||
this._sourceActorIds[url] = actorID;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Make a unique URL from a source that identifies it across reloads.
|
||||
*/
|
||||
getUniqueKey: function (source, originalUrl) {
|
||||
if (originalUrl) {
|
||||
// Original source from a sourcemap.
|
||||
return originalUrl;
|
||||
}
|
||||
|
||||
return getSourceURL(source);
|
||||
}
|
||||
};
|
||||
|
||||
exports.SourceActorStore = SourceActorStore;
|
||||
|
||||
/**
|
||||
* Manages pushing event loops and automatically pops and exits them in the
|
||||
* correct order as they are resolved.
|
||||
*
|
||||
* @param ThreadActor thread
|
||||
* The thread actor instance that owns this EventLoopStack.
|
||||
* @param DebuggerServerConnection connection
|
||||
* The remote protocol connection associated with this event loop stack.
|
||||
* @param Object hooks
|
||||
* An object with the following properties:
|
||||
* - url: The URL string of the debuggee we are spinning an event loop
|
||||
* for.
|
||||
* - preNest: function called before entering a nested event loop
|
||||
* - postNest: function called after exiting a nested event loop
|
||||
*/
|
||||
function EventLoopStack({ thread, connection, hooks }) {
|
||||
this._hooks = hooks;
|
||||
this._thread = thread;
|
||||
this._connection = connection;
|
||||
}
|
||||
|
||||
EventLoopStack.prototype = {
|
||||
/**
|
||||
* The number of nested event loops on the stack.
|
||||
*/
|
||||
get size() {
|
||||
return xpcInspector.eventLoopNestLevel;
|
||||
},
|
||||
|
||||
/**
|
||||
* The URL of the debuggee who pushed the event loop on top of the stack.
|
||||
*/
|
||||
get lastPausedUrl() {
|
||||
let url = null;
|
||||
if (this.size > 0) {
|
||||
try {
|
||||
url = xpcInspector.lastNestRequestor.url;
|
||||
} catch (e) {
|
||||
// The tab's URL getter may throw if the tab is destroyed by the time
|
||||
// this code runs, but we don't really care at this point.
|
||||
dumpn(e);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
/**
|
||||
* The DebuggerServerConnection of the debugger who pushed the event loop on
|
||||
* top of the stack
|
||||
*/
|
||||
get lastConnection() {
|
||||
return xpcInspector.lastNestRequestor._connection;
|
||||
},
|
||||
|
||||
/**
|
||||
* Push a new nested event loop onto the stack.
|
||||
*
|
||||
* @returns EventLoop
|
||||
*/
|
||||
push: function () {
|
||||
return new EventLoop({
|
||||
thread: this._thread,
|
||||
connection: this._connection,
|
||||
hooks: this._hooks
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An object that represents a nested event loop. It is used as the nest
|
||||
* requestor with nsIJSInspector instances.
|
||||
*
|
||||
* @param ThreadActor thread
|
||||
* The thread actor that is creating this nested event loop.
|
||||
* @param DebuggerServerConnection connection
|
||||
* The remote protocol connection associated with this event loop.
|
||||
* @param Object hooks
|
||||
* The same hooks object passed into EventLoopStack during its
|
||||
* initialization.
|
||||
*/
|
||||
function EventLoop({ thread, connection, hooks }) {
|
||||
this._thread = thread;
|
||||
this._hooks = hooks;
|
||||
this._connection = connection;
|
||||
|
||||
this.enter = this.enter.bind(this);
|
||||
this.resolve = this.resolve.bind(this);
|
||||
}
|
||||
|
||||
EventLoop.prototype = {
|
||||
entered: false,
|
||||
resolved: false,
|
||||
get url() {
|
||||
return this._hooks.url;
|
||||
},
|
||||
|
||||
/**
|
||||
* Enter this nested event loop.
|
||||
*/
|
||||
enter: function () {
|
||||
let nestData = this._hooks.preNest
|
||||
? this._hooks.preNest()
|
||||
: null;
|
||||
|
||||
this.entered = true;
|
||||
xpcInspector.enterNestedEventLoop(this);
|
||||
|
||||
// Keep exiting nested event loops while the last requestor is resolved.
|
||||
if (xpcInspector.eventLoopNestLevel > 0) {
|
||||
const { resolved } = xpcInspector.lastNestRequestor;
|
||||
if (resolved) {
|
||||
xpcInspector.exitNestedEventLoop();
|
||||
}
|
||||
}
|
||||
|
||||
if (this._hooks.postNest) {
|
||||
this._hooks.postNest(nestData);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resolve this nested event loop.
|
||||
*
|
||||
* @returns boolean
|
||||
* True if we exited this nested event loop because it was on top of
|
||||
* the stack, false if there is another nested event loop above this
|
||||
* one that hasn't resolved yet.
|
||||
*/
|
||||
resolve: function () {
|
||||
if (!this.entered) {
|
||||
throw new Error("Can't resolve an event loop before it has been entered!");
|
||||
}
|
||||
if (this.resolved) {
|
||||
throw new Error("Already resolved this nested event loop!");
|
||||
}
|
||||
this.resolved = true;
|
||||
if (this === xpcInspector.lastNestRequestor) {
|
||||
xpcInspector.exitNestedEventLoop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* JSD2 actors.
|
||||
*/
|
||||
@ -2092,123 +1736,6 @@ PauseActor.prototype = {
|
||||
actorPrefix: "pause"
|
||||
};
|
||||
|
||||
/**
|
||||
* A base actor for any actors that should only respond receive messages in the
|
||||
* paused state. Subclasses may expose a `threadActor` which is used to help
|
||||
* determine when we are in a paused state. Subclasses should set their own
|
||||
* "constructor" property if they want better error messages. You should never
|
||||
* instantiate a PauseScopedActor directly, only through subclasses.
|
||||
*/
|
||||
function PauseScopedActor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A function decorator for creating methods to handle protocol messages that
|
||||
* should only be received while in the paused state.
|
||||
*
|
||||
* @param method Function
|
||||
* The function we are decorating.
|
||||
*/
|
||||
PauseScopedActor.withPaused = function (method) {
|
||||
return function () {
|
||||
if (this.isPaused()) {
|
||||
return method.apply(this, arguments);
|
||||
}
|
||||
return this._wrongState();
|
||||
};
|
||||
};
|
||||
|
||||
PauseScopedActor.prototype = {
|
||||
|
||||
/**
|
||||
* Returns true if we are in the paused state.
|
||||
*/
|
||||
isPaused: function () {
|
||||
// When there is not a ThreadActor available (like in the webconsole) we
|
||||
// have to be optimistic and assume that we are paused so that we can
|
||||
// respond to requests.
|
||||
return this.threadActor ? this.threadActor.state === "paused" : true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the wrongState response packet for this actor.
|
||||
*/
|
||||
_wrongState: function () {
|
||||
return {
|
||||
error: "wrongState",
|
||||
message: this.constructor.name +
|
||||
" actors can only be accessed while the thread is paused."
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a pause-scoped actor for the specified object.
|
||||
* @see ObjectActor
|
||||
*/
|
||||
function PauseScopedObjectActor(obj, hooks) {
|
||||
ObjectActor.call(this, obj, hooks);
|
||||
this.hooks.promote = hooks.promote;
|
||||
this.hooks.isThreadLifetimePool = hooks.isThreadLifetimePool;
|
||||
}
|
||||
|
||||
PauseScopedObjectActor.prototype = Object.create(PauseScopedActor.prototype);
|
||||
|
||||
Object.assign(PauseScopedObjectActor.prototype, ObjectActor.prototype);
|
||||
|
||||
Object.assign(PauseScopedObjectActor.prototype, {
|
||||
constructor: PauseScopedObjectActor,
|
||||
actorPrefix: "pausedobj",
|
||||
|
||||
onOwnPropertyNames:
|
||||
PauseScopedActor.withPaused(ObjectActor.prototype.onOwnPropertyNames),
|
||||
|
||||
onPrototypeAndProperties:
|
||||
PauseScopedActor.withPaused(ObjectActor.prototype.onPrototypeAndProperties),
|
||||
|
||||
onPrototype: PauseScopedActor.withPaused(ObjectActor.prototype.onPrototype),
|
||||
onProperty: PauseScopedActor.withPaused(ObjectActor.prototype.onProperty),
|
||||
onDecompile: PauseScopedActor.withPaused(ObjectActor.prototype.onDecompile),
|
||||
|
||||
onDisplayString:
|
||||
PauseScopedActor.withPaused(ObjectActor.prototype.onDisplayString),
|
||||
|
||||
onParameterNames:
|
||||
PauseScopedActor.withPaused(ObjectActor.prototype.onParameterNames),
|
||||
|
||||
/**
|
||||
* Handle a protocol request to promote a pause-lifetime grip to a
|
||||
* thread-lifetime grip.
|
||||
*
|
||||
* @param request object
|
||||
* The protocol request object.
|
||||
*/
|
||||
onThreadGrip: PauseScopedActor.withPaused(function (request) {
|
||||
this.hooks.promote();
|
||||
return {};
|
||||
}),
|
||||
|
||||
/**
|
||||
* Handle a protocol request to release a thread-lifetime grip.
|
||||
*
|
||||
* @param request object
|
||||
* The protocol request object.
|
||||
*/
|
||||
onRelease: PauseScopedActor.withPaused(function (request) {
|
||||
if (this.hooks.isThreadLifetimePool()) {
|
||||
return { error: "notReleasable",
|
||||
message: "Only thread-lifetime actors can be released." };
|
||||
}
|
||||
|
||||
this.release();
|
||||
return {};
|
||||
}),
|
||||
});
|
||||
|
||||
Object.assign(PauseScopedObjectActor.prototype.requestTypes, {
|
||||
"threadGrip": PauseScopedObjectActor.prototype.onThreadGrip,
|
||||
});
|
||||
|
||||
function hackDebugger(Debugger) {
|
||||
// TODO: Improve native code instead of hacking on top of it
|
||||
|
173
devtools/server/actors/utils/breakpoint-actor-map.js
Normal file
173
devtools/server/actors/utils/breakpoint-actor-map.js
Normal file
@ -0,0 +1,173 @@
|
||||
/* -*- 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 { OriginalLocation } = require("devtools/server/actors/common");
|
||||
|
||||
/**
|
||||
* A BreakpointActorMap is a map from locations to instances of BreakpointActor.
|
||||
*/
|
||||
function BreakpointActorMap() {
|
||||
this._size = 0;
|
||||
this._actors = {};
|
||||
}
|
||||
|
||||
BreakpointActorMap.prototype = {
|
||||
/**
|
||||
* Return the number of BreakpointActors in this BreakpointActorMap.
|
||||
*
|
||||
* @returns Number
|
||||
* The number of BreakpointActor in this BreakpointActorMap.
|
||||
*/
|
||||
get size() {
|
||||
return this._size;
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate all BreakpointActors that match the given location in
|
||||
* this BreakpointActorMap.
|
||||
*
|
||||
* @param OriginalLocation location
|
||||
* The location for which matching BreakpointActors should be generated.
|
||||
*/
|
||||
findActors: function* (location = new OriginalLocation()) {
|
||||
// Fast shortcut for when we know we won't find any actors. Surprisingly
|
||||
// enough, this speeds up refreshing when there are no breakpoints set by
|
||||
// about 2x!
|
||||
if (this.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
function* findKeys(obj, key) {
|
||||
if (key !== undefined) {
|
||||
if (key in obj) {
|
||||
yield key;
|
||||
}
|
||||
} else {
|
||||
for (key of Object.keys(obj)) {
|
||||
yield key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let query = {
|
||||
sourceActorID: location.originalSourceActor
|
||||
? location.originalSourceActor.actorID
|
||||
: undefined,
|
||||
line: location.originalLine,
|
||||
};
|
||||
|
||||
// If location contains a line, assume we are searching for a whole line
|
||||
// breakpoint, and set begin/endColumn accordingly. Otherwise, we are
|
||||
// searching for all breakpoints, so begin/endColumn should be left unset.
|
||||
if (location.originalLine) {
|
||||
query.beginColumn = location.originalColumn ? location.originalColumn : 0;
|
||||
query.endColumn = location.originalColumn ? location.originalColumn + 1 : Infinity;
|
||||
} else {
|
||||
query.beginColumn = location.originalColumn ? query.originalColumn : undefined;
|
||||
query.endColumn = location.originalColumn ? query.originalColumn + 1 : undefined;
|
||||
}
|
||||
|
||||
for (let sourceActorID of findKeys(this._actors, query.sourceActorID)) {
|
||||
let actor = this._actors[sourceActorID];
|
||||
for (let line of findKeys(actor, query.line)) {
|
||||
for (let beginColumn of findKeys(actor[line], query.beginColumn)) {
|
||||
for (let endColumn of findKeys(actor[line][beginColumn],
|
||||
query.endColumn)) {
|
||||
yield actor[line][beginColumn][endColumn];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the BreakpointActor at the given location in this
|
||||
* BreakpointActorMap.
|
||||
*
|
||||
* @param OriginalLocation location
|
||||
* The location for which the BreakpointActor should be returned.
|
||||
*
|
||||
* @returns BreakpointActor actor
|
||||
* The BreakpointActor at the given location.
|
||||
*/
|
||||
getActor: function (originalLocation) {
|
||||
for (let actor of this.findActors(originalLocation)) {
|
||||
return actor;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the given BreakpointActor to the given location in this
|
||||
* BreakpointActorMap.
|
||||
*
|
||||
* @param OriginalLocation location
|
||||
* The location to which the given BreakpointActor should be set.
|
||||
*
|
||||
* @param BreakpointActor actor
|
||||
* The BreakpointActor to be set to the given location.
|
||||
*/
|
||||
setActor: function (location, actor) {
|
||||
let { originalSourceActor, originalLine, originalColumn } = location;
|
||||
|
||||
let sourceActorID = originalSourceActor.actorID;
|
||||
let line = originalLine;
|
||||
let beginColumn = originalColumn ? originalColumn : 0;
|
||||
let endColumn = originalColumn ? originalColumn + 1 : Infinity;
|
||||
|
||||
if (!this._actors[sourceActorID]) {
|
||||
this._actors[sourceActorID] = [];
|
||||
}
|
||||
if (!this._actors[sourceActorID][line]) {
|
||||
this._actors[sourceActorID][line] = [];
|
||||
}
|
||||
if (!this._actors[sourceActorID][line][beginColumn]) {
|
||||
this._actors[sourceActorID][line][beginColumn] = [];
|
||||
}
|
||||
if (!this._actors[sourceActorID][line][beginColumn][endColumn]) {
|
||||
++this._size;
|
||||
}
|
||||
this._actors[sourceActorID][line][beginColumn][endColumn] = actor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete the BreakpointActor from the given location in this
|
||||
* BreakpointActorMap.
|
||||
*
|
||||
* @param OriginalLocation location
|
||||
* The location from which the BreakpointActor should be deleted.
|
||||
*/
|
||||
deleteActor: function (location) {
|
||||
let { originalSourceActor, originalLine, originalColumn } = location;
|
||||
|
||||
let sourceActorID = originalSourceActor.actorID;
|
||||
let line = originalLine;
|
||||
let beginColumn = originalColumn ? originalColumn : 0;
|
||||
let endColumn = originalColumn ? originalColumn + 1 : Infinity;
|
||||
|
||||
if (this._actors[sourceActorID]) {
|
||||
if (this._actors[sourceActorID][line]) {
|
||||
if (this._actors[sourceActorID][line][beginColumn]) {
|
||||
if (this._actors[sourceActorID][line][beginColumn][endColumn]) {
|
||||
--this._size;
|
||||
}
|
||||
delete this._actors[sourceActorID][line][beginColumn][endColumn];
|
||||
if (Object.keys(this._actors[sourceActorID][line][beginColumn]).length === 0) {
|
||||
delete this._actors[sourceActorID][line][beginColumn];
|
||||
}
|
||||
}
|
||||
if (Object.keys(this._actors[sourceActorID][line]).length === 0) {
|
||||
delete this._actors[sourceActorID][line];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.BreakpointActorMap = BreakpointActorMap;
|
157
devtools/server/actors/utils/event-loop.js
Normal file
157
devtools/server/actors/utils/event-loop.js
Normal file
@ -0,0 +1,157 @@
|
||||
/* -*- 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 xpcInspector = require("xpcInspector");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const { dumpn } = DevToolsUtils;
|
||||
|
||||
/**
|
||||
* Manages pushing event loops and automatically pops and exits them in the
|
||||
* correct order as they are resolved.
|
||||
*
|
||||
* @param ThreadActor thread
|
||||
* The thread actor instance that owns this EventLoopStack.
|
||||
* @param DebuggerServerConnection connection
|
||||
* The remote protocol connection associated with this event loop stack.
|
||||
* @param Object hooks
|
||||
* An object with the following properties:
|
||||
* - url: The URL string of the debuggee we are spinning an event loop
|
||||
* for.
|
||||
* - preNest: function called before entering a nested event loop
|
||||
* - postNest: function called after exiting a nested event loop
|
||||
*/
|
||||
function EventLoopStack({ thread, connection, hooks }) {
|
||||
this._hooks = hooks;
|
||||
this._thread = thread;
|
||||
this._connection = connection;
|
||||
}
|
||||
|
||||
EventLoopStack.prototype = {
|
||||
/**
|
||||
* The number of nested event loops on the stack.
|
||||
*/
|
||||
get size() {
|
||||
return xpcInspector.eventLoopNestLevel;
|
||||
},
|
||||
|
||||
/**
|
||||
* The URL of the debuggee who pushed the event loop on top of the stack.
|
||||
*/
|
||||
get lastPausedUrl() {
|
||||
let url = null;
|
||||
if (this.size > 0) {
|
||||
try {
|
||||
url = xpcInspector.lastNestRequestor.url;
|
||||
} catch (e) {
|
||||
// The tab's URL getter may throw if the tab is destroyed by the time
|
||||
// this code runs, but we don't really care at this point.
|
||||
dumpn(e);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
/**
|
||||
* The DebuggerServerConnection of the debugger who pushed the event loop on
|
||||
* top of the stack
|
||||
*/
|
||||
get lastConnection() {
|
||||
return xpcInspector.lastNestRequestor._connection;
|
||||
},
|
||||
|
||||
/**
|
||||
* Push a new nested event loop onto the stack.
|
||||
*
|
||||
* @returns EventLoop
|
||||
*/
|
||||
push: function () {
|
||||
return new EventLoop({
|
||||
thread: this._thread,
|
||||
connection: this._connection,
|
||||
hooks: this._hooks
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An object that represents a nested event loop. It is used as the nest
|
||||
* requestor with nsIJSInspector instances.
|
||||
*
|
||||
* @param ThreadActor thread
|
||||
* The thread actor that is creating this nested event loop.
|
||||
* @param DebuggerServerConnection connection
|
||||
* The remote protocol connection associated with this event loop.
|
||||
* @param Object hooks
|
||||
* The same hooks object passed into EventLoopStack during its
|
||||
* initialization.
|
||||
*/
|
||||
function EventLoop({ thread, connection, hooks }) {
|
||||
this._thread = thread;
|
||||
this._hooks = hooks;
|
||||
this._connection = connection;
|
||||
|
||||
this.enter = this.enter.bind(this);
|
||||
this.resolve = this.resolve.bind(this);
|
||||
}
|
||||
|
||||
EventLoop.prototype = {
|
||||
entered: false,
|
||||
resolved: false,
|
||||
get url() {
|
||||
return this._hooks.url;
|
||||
},
|
||||
|
||||
/**
|
||||
* Enter this nested event loop.
|
||||
*/
|
||||
enter: function () {
|
||||
let nestData = this._hooks.preNest
|
||||
? this._hooks.preNest()
|
||||
: null;
|
||||
|
||||
this.entered = true;
|
||||
xpcInspector.enterNestedEventLoop(this);
|
||||
|
||||
// Keep exiting nested event loops while the last requestor is resolved.
|
||||
if (xpcInspector.eventLoopNestLevel > 0) {
|
||||
const { resolved } = xpcInspector.lastNestRequestor;
|
||||
if (resolved) {
|
||||
xpcInspector.exitNestedEventLoop();
|
||||
}
|
||||
}
|
||||
|
||||
if (this._hooks.postNest) {
|
||||
this._hooks.postNest(nestData);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resolve this nested event loop.
|
||||
*
|
||||
* @returns boolean
|
||||
* True if we exited this nested event loop because it was on top of
|
||||
* the stack, false if there is another nested event loop above this
|
||||
* one that hasn't resolved yet.
|
||||
*/
|
||||
resolve: function () {
|
||||
if (!this.entered) {
|
||||
throw new Error("Can't resolve an event loop before it has been entered!");
|
||||
}
|
||||
if (this.resolved) {
|
||||
throw new Error("Already resolved this nested event loop!");
|
||||
}
|
||||
this.resolved = true;
|
||||
if (this === xpcInspector.lastNestRequestor) {
|
||||
xpcInspector.exitNestedEventLoop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
exports.EventLoopStack = EventLoopStack;
|
@ -8,10 +8,13 @@ DevToolsModules(
|
||||
'actor-registry-utils.js',
|
||||
'audionodes.json',
|
||||
'automation-timeline.js',
|
||||
'breakpoint-actor-map.js',
|
||||
'css-grid-utils.js',
|
||||
'event-loop.js',
|
||||
'make-debugger.js',
|
||||
'map-uri-to-addon-id.js',
|
||||
'shapes-utils.js',
|
||||
'source-actor-store.js',
|
||||
'stack.js',
|
||||
'TabSources.js',
|
||||
'walker-search.js',
|
||||
|
57
devtools/server/actors/utils/source-actor-store.js
Normal file
57
devtools/server/actors/utils/source-actor-store.js
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- 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";
|
||||
|
||||
loader.lazyRequireGetter(this, "getSourceURL", "devtools/server/actors/source", true);
|
||||
|
||||
/**
|
||||
* Keeps track of persistent sources across reloads and ties different
|
||||
* source instances to the same actor id so that things like
|
||||
* breakpoints survive reloads. ThreadSources uses this to force the
|
||||
* same actorID on a SourceActor.
|
||||
*/
|
||||
function SourceActorStore() {
|
||||
// source identifier --> actor id
|
||||
this._sourceActorIds = Object.create(null);
|
||||
}
|
||||
|
||||
SourceActorStore.prototype = {
|
||||
/**
|
||||
* Lookup an existing actor id that represents this source, if available.
|
||||
*/
|
||||
getReusableActorId: function (source, originalUrl) {
|
||||
let url = this.getUniqueKey(source, originalUrl);
|
||||
if (url && url in this._sourceActorIds) {
|
||||
return this._sourceActorIds[url];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a source with an actorID.
|
||||
*/
|
||||
setReusableActorId: function (source, originalUrl, actorID) {
|
||||
let url = this.getUniqueKey(source, originalUrl);
|
||||
if (url) {
|
||||
this._sourceActorIds[url] = actorID;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Make a unique URL from a source that identifies it across reloads.
|
||||
*/
|
||||
getUniqueKey: function (source, originalUrl) {
|
||||
if (originalUrl) {
|
||||
// Original source from a sourcemap.
|
||||
return originalUrl;
|
||||
}
|
||||
|
||||
return getSourceURL(source);
|
||||
}
|
||||
};
|
||||
|
||||
exports.SourceActorStore = SourceActorStore;
|
@ -11,7 +11,7 @@
|
||||
const Services = require("Services");
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { DebuggerServer, ActorPool } = require("devtools/server/main");
|
||||
const { ThreadActor } = require("devtools/server/actors/script");
|
||||
const { ThreadActor } = require("devtools/server/actors/thread");
|
||||
const { ObjectActor, LongStringActor, createValueGrip, stringIsLong } = require("devtools/server/actors/object");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const ErrorDocs = require("devtools/server/actors/errordocs");
|
||||
|
@ -11,7 +11,7 @@ const { ChromeActor } = require("./chrome");
|
||||
const makeDebugger = require("./utils/make-debugger");
|
||||
|
||||
loader.lazyRequireGetter(this, "mapURIToAddonID", "devtools/server/actors/utils/map-uri-to-addon-id");
|
||||
loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/script", true);
|
||||
loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/thread", true);
|
||||
loader.lazyRequireGetter(this, "ChromeUtils");
|
||||
|
||||
const FALLBACK_DOC_MESSAGE = "Your addon does not have any document opened yet.";
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
// Test the functionality of the BreakpointActorMap object.
|
||||
|
||||
const { BreakpointActorMap } = require("devtools/server/actors/script");
|
||||
const { BreakpointActorMap } = require("devtools/server/actors/utils/breakpoint-actor-map");
|
||||
|
||||
function run_test() {
|
||||
test_get_actor();
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/server/actors/common");
|
||||
const { RootActor } = require("devtools/server/actors/root");
|
||||
const { ThreadActor } = require("devtools/server/actors/script");
|
||||
const { ThreadActor } = require("devtools/server/actors/thread");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const { TabSources } = require("devtools/server/actors/utils/TabSources");
|
||||
const makeDebugger = require("devtools/server/actors/utils/make-debugger");
|
||||
|
@ -30,7 +30,7 @@ loadSubScript("resource://devtools/shared/worker/loader.js");
|
||||
|
||||
var defer = worker.require("devtools/shared/defer");
|
||||
var { ActorPool } = worker.require("devtools/server/actors/common");
|
||||
var { ThreadActor } = worker.require("devtools/server/actors/script");
|
||||
var { ThreadActor } = worker.require("devtools/server/actors/thread");
|
||||
var { WebConsoleActor } = worker.require("devtools/server/actors/webconsole");
|
||||
var { TabSources } = worker.require("devtools/server/actors/utils/TabSources");
|
||||
var makeDebugger = worker.require("devtools/server/actors/utils/make-debugger");
|
||||
|
@ -6,7 +6,7 @@
|
||||
const { ActorPool, appendExtraActors, createExtraActors } =
|
||||
require("devtools/server/actors/common");
|
||||
const { RootActor } = require("devtools/server/actors/root");
|
||||
const { ThreadActor } = require("devtools/server/actors/script");
|
||||
const { ThreadActor } = require("devtools/server/actors/thread");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const promise = require("promise");
|
||||
|
||||
|
@ -98,7 +98,7 @@ consoleService.registerListener(listener);
|
||||
* Initialize the testing debugger server.
|
||||
*/
|
||||
function initTestDebuggerServer() {
|
||||
DebuggerServer.registerModule("devtools/server/actors/script", {
|
||||
DebuggerServer.registerModule("devtools/server/actors/thread", {
|
||||
prefix: "script",
|
||||
constructor: "ScriptActor",
|
||||
type: { global: true, tab: true }
|
||||
|
@ -5,7 +5,7 @@
|
||||
const { ActorPool, appendExtraActors, createExtraActors } =
|
||||
require("devtools/server/actors/common");
|
||||
const { RootActor } = require("devtools/server/actors/root");
|
||||
const { ThreadActor } = require("devtools/server/actors/script");
|
||||
const { ThreadActor } = require("devtools/server/actors/thread");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const promise = require("promise");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user