зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1494796 - Convert ThreadClient into a Front; r=jdescottes
This is the first part of the threadClient refactor. It only moves the methods to the new front. and does some basic fixes. Differential Revision: https://phabricator.services.mozilla.com/D32692 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
57a1e6ce79
Коммит
650d7f9c31
|
@ -3,7 +3,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const ThreadClient = require("devtools/shared/client/thread-client");
|
||||
const { ThreadClient } = require("devtools/shared/client/thread-client");
|
||||
const { BrowsingContextTargetFront } = require("devtools/shared/fronts/targets/browsing-context");
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,7 +20,7 @@ loader.lazyRequireGetter(this, "DebuggerSocket", "devtools/shared/security/socke
|
|||
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
||||
|
||||
loader.lazyRequireGetter(this, "RootFront", "devtools/shared/fronts/root", true);
|
||||
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client");
|
||||
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client", true);
|
||||
loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/object-client");
|
||||
loader.lazyRequireGetter(this, "Front", "devtools/shared/protocol", true);
|
||||
|
||||
|
@ -230,7 +230,7 @@ DebuggerClient.prototype = {
|
|||
return;
|
||||
}
|
||||
if (client.detach) {
|
||||
client.detach(detachClients);
|
||||
client.detach().then(detachClients);
|
||||
return;
|
||||
}
|
||||
detachClients();
|
||||
|
@ -248,22 +248,16 @@ DebuggerClient.prototype = {
|
|||
* @param object options
|
||||
* Configuration options.
|
||||
*/
|
||||
attachThread: function(threadActor, options = {}) {
|
||||
attachThread: async function(threadActor, options = {}) {
|
||||
if (this._clients.has(threadActor)) {
|
||||
const client = this._clients.get(threadActor);
|
||||
return promise.resolve([{}, client]);
|
||||
}
|
||||
|
||||
const packet = {
|
||||
to: threadActor,
|
||||
type: "attach",
|
||||
options,
|
||||
};
|
||||
return this.request(packet).then(response => {
|
||||
const threadClient = new ThreadClient(this, threadActor);
|
||||
this.registerClient(threadClient);
|
||||
return [response, threadClient];
|
||||
});
|
||||
const threadClient = new ThreadClient(this, threadActor);
|
||||
const response = await threadClient.attach(options);
|
||||
this.registerClient(threadClient);
|
||||
return [response, threadClient];
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {ThreadStateTypes} = require("devtools/shared/client/constants");
|
||||
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
|
||||
const { threadSpec } = require("devtools/shared/specs/thread");
|
||||
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
|
@ -30,40 +30,42 @@ loader.lazyRequireGetter(
|
|||
* @param actor string
|
||||
* The actor ID for this thread.
|
||||
*/
|
||||
function ThreadClient(client, actor) {
|
||||
this.client = client;
|
||||
this._actor = actor;
|
||||
this._pauseGrips = {};
|
||||
this._threadGrips = {};
|
||||
this.request = this.client.request;
|
||||
}
|
||||
class ThreadClient extends FrontClassWithSpec(threadSpec) {
|
||||
constructor(client, actor) {
|
||||
super(client);
|
||||
this.events = ["newSource", "progress"];
|
||||
this.client = client;
|
||||
this._pauseGrips = {};
|
||||
this._threadGrips = {};
|
||||
this._state = "paused";
|
||||
this.actorID = actor;
|
||||
this.manage(this);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.client.unregisterClient(this);
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
ThreadClient.prototype = {
|
||||
_state: "paused",
|
||||
get state() {
|
||||
return this._state;
|
||||
},
|
||||
}
|
||||
|
||||
get paused() {
|
||||
return this._state === "paused";
|
||||
},
|
||||
|
||||
_actor: null,
|
||||
}
|
||||
|
||||
get actor() {
|
||||
return this._actor;
|
||||
},
|
||||
return this.actorID;
|
||||
}
|
||||
|
||||
get _transport() {
|
||||
return this.client._transport;
|
||||
},
|
||||
|
||||
_assertPaused: function(command) {
|
||||
_assertPaused(command) {
|
||||
if (!this.paused) {
|
||||
throw Error(
|
||||
command + " command sent while not paused. Currently " + this._state
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume a paused thread. If the optional limit parameter is present, then
|
||||
|
@ -78,111 +80,94 @@ ThreadClient.prototype = {
|
|||
* than proceeding forwards. This parameter has no effect if the
|
||||
* server does not support rewinding.
|
||||
*/
|
||||
_doResume: DebuggerClient.requester({
|
||||
type: "resume",
|
||||
resumeLimit: arg(0),
|
||||
rewind: arg(1),
|
||||
}, {
|
||||
before: function(packet) {
|
||||
this._assertPaused("resume");
|
||||
async _doResume(resumeLimit, rewind) {
|
||||
this._assertPaused("resume");
|
||||
|
||||
// Put the client in a tentative "resuming" state so we can prevent
|
||||
// further requests that should only be sent in the paused state.
|
||||
this._previousState = this._state;
|
||||
this._state = "resuming";
|
||||
|
||||
return packet;
|
||||
},
|
||||
after: function(response) {
|
||||
if (response.error && this._state == "resuming") {
|
||||
// Put the client in a tentative "resuming" state so we can prevent
|
||||
// further requests that should only be sent in the paused state.
|
||||
this._previousState = this._state;
|
||||
this._state = "resuming";
|
||||
try {
|
||||
await super.resume(resumeLimit, rewind);
|
||||
} catch (e) {
|
||||
if (this._state == "resuming") {
|
||||
// There was an error resuming, update the state to the new one
|
||||
// reported by the server, if given (only on wrongState), otherwise
|
||||
// reset back to the previous state.
|
||||
if (response.state) {
|
||||
this._state = ThreadStateTypes[response.state];
|
||||
if (e.state) {
|
||||
this._state = ThreadStateTypes[e.state];
|
||||
} else {
|
||||
this._state = this._previousState;
|
||||
}
|
||||
}
|
||||
delete this._previousState;
|
||||
return response;
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconfigure the thread actor.
|
||||
*
|
||||
* @param object options
|
||||
* A dictionary object of the new options to use in the thread actor.
|
||||
*/
|
||||
reconfigure: DebuggerClient.requester({
|
||||
type: "reconfigure",
|
||||
options: arg(0),
|
||||
}),
|
||||
delete this._previousState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume a paused thread.
|
||||
*/
|
||||
resume: function() {
|
||||
resume() {
|
||||
return this._doResume(null, false);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume then pause without stepping.
|
||||
*
|
||||
*/
|
||||
resumeThenPause: function() {
|
||||
resumeThenPause() {
|
||||
return this._doResume({ type: "break" }, false);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind a thread until a breakpoint is hit.
|
||||
*/
|
||||
rewind: function() {
|
||||
return this._doResume(null, true);
|
||||
},
|
||||
rewind() {
|
||||
this._doResume(null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Step over a function call.
|
||||
*/
|
||||
stepOver: function() {
|
||||
stepOver() {
|
||||
return this._doResume({ type: "next" }, false);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Step into a function call.
|
||||
*/
|
||||
stepIn: function() {
|
||||
stepIn() {
|
||||
return this._doResume({ type: "step" }, false);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Step out of a function call.
|
||||
*/
|
||||
stepOut: function() {
|
||||
stepOut() {
|
||||
return this._doResume({ type: "finish" }, false);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind step over a function call.
|
||||
*/
|
||||
reverseStepOver: function() {
|
||||
reverseStepOver() {
|
||||
return this._doResume({ type: "next" }, true);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately interrupt a running thread.
|
||||
*/
|
||||
interrupt: function() {
|
||||
interrupt() {
|
||||
return this._doInterrupt(null);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause execution right before the next JavaScript bytecode is executed.
|
||||
*/
|
||||
breakOnNext: function() {
|
||||
breakOnNext() {
|
||||
return this._doInterrupt("onNext");
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Warp through time to an execution point in the past or future.
|
||||
|
@ -190,7 +175,7 @@ ThreadClient.prototype = {
|
|||
* @param object aTarget
|
||||
* Description of the warp destination.
|
||||
*/
|
||||
timeWarp: function(target) {
|
||||
timeWarp(target) {
|
||||
const warp = () => {
|
||||
this._doResume({ type: "warp", target }, true);
|
||||
};
|
||||
|
@ -198,59 +183,30 @@ ThreadClient.prototype = {
|
|||
return warp();
|
||||
}
|
||||
return this.interrupt().then(warp);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupt a running thread.
|
||||
*/
|
||||
_doInterrupt: DebuggerClient.requester({
|
||||
type: "interrupt",
|
||||
when: arg(0),
|
||||
}),
|
||||
|
||||
/**
|
||||
* Enable or disable pausing when an exception is thrown.
|
||||
*
|
||||
* @param boolean pauseOnExceptions
|
||||
* Enables pausing if true, disables otherwise.
|
||||
* @param boolean ignoreCaughtExceptions
|
||||
* Whether to ignore caught exceptions
|
||||
*/
|
||||
pauseOnExceptions: DebuggerClient.requester({
|
||||
type: "pauseOnExceptions",
|
||||
pauseOnExceptions: arg(0),
|
||||
ignoreCaughtExceptions: arg(1),
|
||||
}),
|
||||
_doInterrupt(when) {
|
||||
return super.interrupt(when);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach from the thread actor.
|
||||
*/
|
||||
detach: DebuggerClient.requester({
|
||||
type: "detach",
|
||||
}, {
|
||||
after: function(response) {
|
||||
this.client.unregisterClient(this);
|
||||
return response;
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* Promote multiple pause-lifetime object actors to thread-lifetime ones.
|
||||
*
|
||||
* @param array actors
|
||||
* An array with actor IDs to promote.
|
||||
*/
|
||||
threadGrips: DebuggerClient.requester({
|
||||
type: "threadGrips",
|
||||
actors: arg(0),
|
||||
}),
|
||||
async detach() {
|
||||
const response = await super.detach();
|
||||
this.client.unregisterClient(this);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the loaded sources for the current thread.
|
||||
*/
|
||||
getSources: DebuggerClient.requester({
|
||||
type: "sources",
|
||||
}),
|
||||
getSources() {
|
||||
return super.sources();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request frames from the callstack for the current thread.
|
||||
|
@ -262,31 +218,18 @@ ThreadClient.prototype = {
|
|||
* The maximum number of frames to return, or null to return all
|
||||
* frames.
|
||||
*/
|
||||
getFrames: DebuggerClient.requester({
|
||||
type: "frames",
|
||||
start: arg(0),
|
||||
count: arg(1),
|
||||
}),
|
||||
|
||||
/**
|
||||
* Toggle pausing via breakpoints in the server.
|
||||
*
|
||||
* @param skip boolean
|
||||
* Whether the server should skip pausing via breakpoints
|
||||
*/
|
||||
skipBreakpoints: DebuggerClient.requester({
|
||||
type: "skipBreakpoints",
|
||||
skip: arg(0),
|
||||
}),
|
||||
getFrames(start, count) {
|
||||
return super.frames(start, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the frame environment.
|
||||
*
|
||||
* @param frameId string
|
||||
*/
|
||||
getEnvironment: function(frameId) {
|
||||
return this.request({ to: frameId, type: "getEnvironment" });
|
||||
},
|
||||
getEnvironment(frameId) {
|
||||
return this.client.request({ to: frameId, type: "getEnvironment" });
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a ObjectClient object for the given object grip.
|
||||
|
@ -294,7 +237,7 @@ ThreadClient.prototype = {
|
|||
* @param grip object
|
||||
* A pause-lifetime object grip returned by the protocol.
|
||||
*/
|
||||
pauseGrip: function(grip) {
|
||||
pauseGrip(grip) {
|
||||
if (grip.actor in this._pauseGrips) {
|
||||
return this._pauseGrips[grip.actor];
|
||||
}
|
||||
|
@ -302,7 +245,7 @@ ThreadClient.prototype = {
|
|||
const client = new ObjectClient(this.client, grip);
|
||||
this._pauseGrips[grip.actor] = client;
|
||||
return client;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear and invalidate all the grip clients from the given cache.
|
||||
|
@ -310,34 +253,33 @@ ThreadClient.prototype = {
|
|||
* @param gripCacheName
|
||||
* The property name of the grip cache we want to clear.
|
||||
*/
|
||||
_clearObjectClients: function(gripCacheName) {
|
||||
_clearObjectClients(gripCacheName) {
|
||||
for (const id in this[gripCacheName]) {
|
||||
this[gripCacheName][id].valid = false;
|
||||
}
|
||||
this[gripCacheName] = {};
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate pause-lifetime grip clients and clear the list of current grip
|
||||
* clients.
|
||||
*/
|
||||
_clearPauseGrips: function() {
|
||||
_clearPauseGrips() {
|
||||
this._clearObjectClients("_pauseGrips");
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate thread-lifetime grip clients and clear the list of current grip
|
||||
* clients.
|
||||
*/
|
||||
_clearThreadGrips: function() {
|
||||
_clearThreadGrips() {
|
||||
this._clearObjectClients("_threadGrips");
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle thread state change by doing necessary cleanup and notifying all
|
||||
* registered listeners.
|
||||
* Handle thread state change by doing necessary cleanup
|
||||
*/
|
||||
_onThreadState: function(packet) {
|
||||
_onThreadState(packet) {
|
||||
this._state = ThreadStateTypes[packet.type];
|
||||
// The debugger UI may not be initialized yet so we want to keep
|
||||
// the packet around so it knows what to pause state to display
|
||||
|
@ -346,84 +288,24 @@ ThreadClient.prototype = {
|
|||
this._clearPauseGrips();
|
||||
packet.type === ThreadStateTypes.detached && this._clearThreadGrips();
|
||||
this.client._eventsEnabled && this.emit(packet.type, packet);
|
||||
},
|
||||
}
|
||||
|
||||
getLastPausePacket: function() {
|
||||
getLastPausePacket() {
|
||||
return this._lastPausePacket;
|
||||
},
|
||||
|
||||
setBreakpoint: DebuggerClient.requester({
|
||||
type: "setBreakpoint",
|
||||
location: arg(0),
|
||||
options: arg(1),
|
||||
}),
|
||||
|
||||
removeBreakpoint: DebuggerClient.requester({
|
||||
type: "removeBreakpoint",
|
||||
location: arg(0),
|
||||
}),
|
||||
|
||||
/**
|
||||
* Requests to set XHR breakpoint
|
||||
* @param string path
|
||||
* pause when url contains `path`
|
||||
* @param string method
|
||||
* pause when method of request is `method`
|
||||
*/
|
||||
setXHRBreakpoint: DebuggerClient.requester({
|
||||
type: "setXHRBreakpoint",
|
||||
path: arg(0),
|
||||
method: arg(1),
|
||||
}),
|
||||
|
||||
/**
|
||||
* Request to remove XHR breakpoint
|
||||
* @param string path
|
||||
* @param string method
|
||||
*/
|
||||
removeXHRBreakpoint: DebuggerClient.requester({
|
||||
type: "removeXHRBreakpoint",
|
||||
path: arg(0),
|
||||
method: arg(1),
|
||||
}),
|
||||
|
||||
/**
|
||||
* Request to get the set of available event breakpoints.
|
||||
*/
|
||||
getAvailableEventBreakpoints: DebuggerClient.requester({
|
||||
type: "getAvailableEventBreakpoints",
|
||||
}),
|
||||
|
||||
/**
|
||||
* Request to get the IDs of the active event breakpoints.
|
||||
*/
|
||||
getActiveEventBreakpoints: DebuggerClient.requester({
|
||||
type: "getActiveEventBreakpoints",
|
||||
}),
|
||||
|
||||
/**
|
||||
* Request to set the IDs of the active event breakpoints.
|
||||
*/
|
||||
setActiveEventBreakpoints: DebuggerClient.requester({
|
||||
type: "setActiveEventBreakpoints",
|
||||
ids: arg(0),
|
||||
}),
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of SourceFront for the given source actor form.
|
||||
*/
|
||||
source: function(form) {
|
||||
source(form) {
|
||||
if (form.actor in this._threadGrips) {
|
||||
return this._threadGrips[form.actor];
|
||||
}
|
||||
|
||||
this._threadGrips[form.actor] = new SourceFront(this.client, form);
|
||||
return this._threadGrips[form.actor];
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
events: ["newSource", "progress"],
|
||||
};
|
||||
|
||||
EventEmitter.decorate(ThreadClient.prototype);
|
||||
|
||||
module.exports = ThreadClient;
|
||||
exports.ThreadClient = ThreadClient;
|
||||
registerFront(ThreadClient);
|
||||
|
|
|
@ -19,11 +19,17 @@ const { ArrayBufferFront } = require("devtools/shared/fronts/array-buffer");
|
|||
class SourceFront extends FrontClassWithSpec(sourceSpec) {
|
||||
constructor(client, form) {
|
||||
super(client);
|
||||
this._url = form.url;
|
||||
// this is here for the time being, until the source front is managed
|
||||
// via protocol.js marshalling
|
||||
this.actorID = form.actor;
|
||||
this.manage(this);
|
||||
if (form) {
|
||||
this._url = form.url;
|
||||
// this is here for the time being, until the source front is managed
|
||||
// via protocol.js marshalling
|
||||
this.actorID = form.actor;
|
||||
this.manage(this);
|
||||
}
|
||||
}
|
||||
|
||||
form(json) {
|
||||
this._url = json.url;
|
||||
}
|
||||
|
||||
get actor() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче