Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / devtools / client / fronts / thread.js
blob8b774e7504f29a845c081590f8e6b1b281cdff2c
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const { ThreadStateTypes } = require("resource://devtools/client/constants.js");
8 const {
9 FrontClassWithSpec,
10 registerFront,
11 } = require("resource://devtools/shared/protocol.js");
13 const { threadSpec } = require("resource://devtools/shared/specs/thread.js");
15 loader.lazyRequireGetter(
16 this,
17 "ObjectFront",
18 "resource://devtools/client/fronts/object.js",
19 true
21 loader.lazyRequireGetter(
22 this,
23 "FrameFront",
24 "resource://devtools/client/fronts/frame.js"
26 loader.lazyRequireGetter(
27 this,
28 "SourceFront",
29 "resource://devtools/client/fronts/source.js",
30 true
33 /**
34 * Creates a thread front for the remote debugging protocol server. This client
35 * is a front to the thread actor created in the server side, hiding the
36 * protocol details in a traditional JavaScript API.
38 * @param client DevToolsClient
39 * @param actor string
40 * The actor ID for this thread.
42 class ThreadFront extends FrontClassWithSpec(threadSpec) {
43 constructor(client, targetFront, parentFront) {
44 super(client, targetFront, parentFront);
45 this.client = client;
46 this._threadGrips = {};
47 // Note that this isn't matching ThreadActor state field.
48 // ThreadFront is only using two values: paused or attached.
49 this._state = "attached";
51 this._beforePaused = this._beforePaused.bind(this);
52 this._beforeResumed = this._beforeResumed.bind(this);
53 this.before("paused", this._beforePaused);
54 this.before("resumed", this._beforeResumed);
55 this.targetFront.on("will-navigate", this._onWillNavigate.bind(this));
56 // Attribute name from which to retrieve the actorID out of the target actor's form
57 this.formAttributeName = "threadActor";
60 get state() {
61 return this._state;
64 get paused() {
65 return this._state === "paused";
68 get actor() {
69 return this.actorID;
72 _assertPaused(command) {
73 if (!this.paused) {
74 throw Error(
75 command + " command sent while not paused. Currently " + this._state
80 getFrames(start, count) {
81 return super.frames(start, count);
84 /**
85 * Resume a paused thread. If the optional limit parameter is present, then
86 * the thread will also pause when that limit is reached.
88 * @param [optional] object limit
89 * An object with a type property set to the appropriate limit (next,
90 * step, or finish) per the remote debugging protocol specification.
91 * Use null to specify no limit.
93 async _doResume(resumeLimit, frameActorID) {
94 this._assertPaused("resume");
96 // Put the client in a tentative "resuming" state so we can prevent
97 // further requests that should only be sent in the paused state.
98 this._previousState = this._state;
99 this._state = "resuming";
100 try {
101 await super.resume(resumeLimit, frameActorID);
102 } catch (e) {
103 if (this._state == "resuming") {
104 // There was an error resuming, update the state to the new one
105 // reported by the server, if given (only on wrongState), otherwise
106 // reset back to the previous state.
107 if (e.state) {
108 this._state = ThreadStateTypes[e.state];
109 } else {
110 this._state = this._previousState;
115 delete this._previousState;
119 * Resume a paused thread.
121 resume() {
122 return this._doResume(null);
126 * Resume then pause without stepping.
129 resumeThenPause() {
130 return this._doResume({ type: "break" });
134 * Step over a function call.
136 stepOver(frameActorID) {
137 return this._doResume({ type: "next" }, frameActorID);
141 * Step into a function call.
143 stepIn(frameActorID) {
144 return this._doResume({ type: "step" }, frameActorID);
148 * Step out of a function call.
150 stepOut(frameActorID) {
151 return this._doResume({ type: "finish" }, frameActorID);
155 * Restart selected frame.
157 restart(frameActorID) {
158 return this._doResume({ type: "restart" }, frameActorID);
162 * Immediately interrupt a running thread.
164 interrupt() {
165 return this._doInterrupt(null);
169 * Pause execution right before the next JavaScript bytecode is executed.
171 breakOnNext() {
172 return this._doInterrupt("onNext");
176 * Interrupt a running thread.
178 _doInterrupt(when) {
179 return super.interrupt(when);
183 * Request the loaded sources for the current thread.
185 async getSources() {
186 let sources = [];
187 try {
188 sources = await super.sources();
189 } catch (e) {
190 // we may have closed the connection
191 console.log(`getSources failed. Connection may have closed: ${e}`);
193 return { sources };
197 * This is only used by tests, which should be migrated to DevToolsClient.createObjectFront
199 pauseGrip(grip) {
200 return new ObjectFront(this.conn, this.targetFront, this, grip);
204 * Clear and invalidate all the grip fronts from the given cache.
206 * @param gripCacheName
207 * The property name of the grip cache we want to clear.
209 _clearObjectFronts(gripCacheName) {
210 for (const id in this[gripCacheName]) {
211 this[gripCacheName][id].valid = false;
213 this[gripCacheName] = {};
216 _beforePaused(packet) {
217 this._state = "paused";
218 this._onThreadState(packet);
221 _beforeResumed() {
222 this._state = "attached";
223 this._onThreadState(null);
224 this.unmanageChildren(FrameFront);
227 _onWillNavigate() {
228 this.unmanageChildren(SourceFront);
232 * Handle thread state change by doing necessary cleanup
234 _onThreadState(packet) {
235 // The debugger UI may not be initialized yet so we want to keep
236 // the packet around so it knows what to pause state to display
237 // when it's initialized
238 this._lastPausePacket = packet;
241 getLastPausePacket() {
242 return this._lastPausePacket;
246 * Return an instance of SourceFront for the given source actor form.
248 source(form) {
249 if (form.actor in this._threadGrips) {
250 return this._threadGrips[form.actor];
253 const sourceFront = new SourceFront(this.client, form);
254 this.manage(sourceFront);
255 this._threadGrips[form.actor] = sourceFront;
256 return sourceFront;
260 exports.ThreadFront = ThreadFront;
261 registerFront(ThreadFront);