Backed out 5 changesets (bug 1619622) for causing devtool failures in browser_dbg-browser-content-toolbox.js

CLOSED TREE

Backed out changeset d447fd6fa18d (bug 1619622)
Backed out changeset f2ac72165a3a (bug 1619622)
Backed out changeset ceeaf109d8b6 (bug 1619622)
Backed out changeset 778c166fd33f (bug 1619622)
Backed out changeset 9a2b75a25794 (bug 1619622)
This commit is contained in:
Mihai Alexandru Michis 2020-03-11 21:17:35 +02:00
parent 78ccb02f0a
commit 6aff1e4070
24 changed files with 113 additions and 129 deletions

View File

@ -4,7 +4,11 @@
// @flow
import { setupCommands, clientCommands } from "./firefox/commands";
import {
setupCommands,
setupCommandsTopTarget,
clientCommands,
} from "./firefox/commands";
import {
removeEventsTopTarget,
setupEvents,
@ -19,7 +23,7 @@ export async function onConnect(connection: any, _actions: Object) {
const { devToolsClient, targetList } = connection;
actions = _actions;
setupCommands({ devToolsClient, targetList });
setupCommands({ devToolsClient });
setupEvents({ actions, devToolsClient });
await targetList.watchTargets(
targetList.ALL_TYPES,
@ -50,6 +54,7 @@ async function onTargetAvailable({
return;
}
setupCommandsTopTarget(targetFront);
setupEventsTopTarget(targetFront);
targetFront.on("will-navigate", actions.willNavigate);
targetFront.on("navigate", actions.navigated);
@ -93,9 +98,6 @@ async function onTargetAvailable({
await clientCommands.checkIfAlreadyPaused();
}
// TODO: optimize the thread updates to only update according to what changed
// i.e. just about this one target
await actions.updateThreads();
}
function onTargetDestroyed({ targetFront, isTopLevel }) {
@ -104,9 +106,6 @@ function onTargetDestroyed({ targetFront, isTopLevel }) {
targetFront.off("navigate", actions.navigated);
removeEventsTopTarget(targetFront);
}
// TODO: optimize the thread updates to only update according to what changed
// i.e. just about this one target
actions.updateThreads();
}
export { clientCommands, clientEvents };

View File

@ -29,7 +29,6 @@ import type {
import type {
Target,
DevToolsClient,
TargetList,
Grip,
ThreadFront,
ObjectFront,
@ -43,8 +42,9 @@ import type {
} from "../../actions/types";
let targets: { [string]: Target };
let currentThreadFront: ThreadFront;
let currentTarget: Target;
let devToolsClient: DevToolsClient;
let targetList: TargetList;
let sourceActors: { [ActorId]: SourceId };
let breakpoints: { [string]: Object };
let eventBreakpoints: ?EventListenerActiveList;
@ -53,23 +53,18 @@ const CALL_STACK_PAGE_SIZE = 1000;
type Dependencies = {
devToolsClient: DevToolsClient,
targetList: TargetList,
};
function setupCommands(dependencies: Dependencies) {
devToolsClient = dependencies.devToolsClient;
targetList = dependencies.targetList;
targets = {};
sourceActors = {};
breakpoints = {};
}
function currentTarget(): Target {
return targetList.targetFront;
}
function currentThreadFront(): ThreadFront {
return currentTarget().threadFront;
function setupCommandsTopTarget(targetFront: Target) {
currentTarget = targetFront;
currentThreadFront = targetFront.threadFront;
}
function createObjectFront(grip: Grip): ObjectFront {
@ -77,7 +72,7 @@ function createObjectFront(grip: Grip): ObjectFront {
throw new Error("Actor is missing");
}
return devToolsClient.createObjectFront(grip, currentThreadFront());
return devToolsClient.createObjectFront(grip, currentThreadFront);
}
async function loadObjectProperties(root: Node) {
@ -113,8 +108,8 @@ function getTargetsMap(): { string: Target } {
}
function lookupTarget(thread: string) {
if (thread == currentThreadFront().actor) {
return currentTarget();
if (thread == currentThreadFront.actor) {
return currentTarget;
}
const targetsMap = getTargetsMap();
@ -131,8 +126,8 @@ function lookupThreadFront(thread: string) {
}
function listThreadFronts() {
const list = (Object.values(getTargetsMap()): any);
return list.map(target => target.threadFront).filter(t => !!t);
const targetList = (Object.values(getTargetsMap()): any);
return targetList.map(target => target.threadFront).filter(t => !!t);
}
function forEachThread(iteratee) {
@ -142,7 +137,7 @@ function forEachThread(iteratee) {
// resolve in FIFO order, and this could result in client and server state
// going out of sync.
const promises = [currentThreadFront(), ...listThreadFronts()].map(
const promises = [currentThreadFront, ...listThreadFronts()].map(
// If a thread shuts down while sending the message then it will
// throw. Ignore these exceptions.
t => iteratee(t).catch(e => console.log(e))
@ -182,11 +177,11 @@ async function sourceContents({
}
function setXHRBreakpoint(path: string, method: string) {
return currentThreadFront().setXHRBreakpoint(path, method);
return currentThreadFront.setXHRBreakpoint(path, method);
}
function removeXHRBreakpoint(path: string, method: string) {
return currentThreadFront().removeXHRBreakpoint(path, method);
return currentThreadFront.removeXHRBreakpoint(path, method);
}
function addWatchpoint(
@ -195,14 +190,14 @@ function addWatchpoint(
label: string,
watchpointType: string
) {
if (currentTarget().traits.watchpoints) {
if (currentTarget.traits.watchpoints) {
const objectFront = createObjectFront(object);
return objectFront.addWatchpoint(property, label, watchpointType);
}
}
async function removeWatchpoint(object: Grip, property: string) {
if (currentTarget().traits.watchpoints) {
if (currentTarget.traits.watchpoints) {
const objectFront = createObjectFront(object);
await objectFront.removeWatchpoint(property);
}
@ -254,11 +249,11 @@ async function evaluate(
{ thread, frameId }: EvaluateParam = {}
): Promise<{ result: ExpressionResult }> {
const params = { thread, frameActor: frameId };
if (!currentTarget() || !script) {
if (!currentTarget || !script) {
return { result: null };
}
const target = thread ? lookupTarget(thread) : currentTarget();
const target = thread ? lookupTarget(thread) : currentTarget;
const consoleFront = await target.getFront("console");
if (!consoleFront) {
return { result: null };
@ -272,10 +267,10 @@ async function autocomplete(
cursor: number,
frameId: ?string
): Promise<mixed> {
if (!currentTarget() || !input) {
if (!currentTarget || !input) {
return {};
}
const consoleFront = await currentTarget().getFront("console");
const consoleFront = await currentTarget.getFront("console");
if (!consoleFront) {
return {};
}
@ -291,11 +286,11 @@ async function autocomplete(
}
function navigate(url: string): Promise<*> {
return currentTarget().navigateTo({ url });
return currentTarget.navigateTo({ url });
}
function reload(): Promise<*> {
return currentTarget().reload();
return currentTarget.reload();
}
function getProperties(thread: string, grip: Grip): Promise<*> {
@ -343,7 +338,7 @@ async function blackBox(
isBlackBoxed: boolean,
range?: Range
): Promise<*> {
const sourceFront = currentThreadFront().source({ actor: sourceActor.actor });
const sourceFront = currentThreadFront.source({ actor: sourceActor.actor });
if (isBlackBoxed) {
await sourceFront.unblackBox(range);
} else {
@ -369,7 +364,7 @@ function setEventListenerBreakpoints(ids: string[]) {
async function getEventListenerBreakpointTypes(): Promise<EventListenerCategoryList> {
let categories;
try {
categories = await currentThreadFront().getAvailableEventBreakpoints();
categories = await currentThreadFront.getAvailableEventBreakpoints();
if (!Array.isArray(categories)) {
// When connecting to older browser that had our placeholder
@ -409,7 +404,7 @@ async function toggleEventLogging(logEventBreakpoints: boolean) {
}
function getAllThreadFronts() {
const fronts = [currentThreadFront()];
const fronts = [currentThreadFront];
for (const { threadFront } of (Object.values(targets): any)) {
fronts.push(threadFront);
}
@ -458,10 +453,10 @@ async function fetchThreads() {
};
await updateTargets({
currentTarget,
devToolsClient,
targets,
options,
targetList,
});
// eslint-disable-next-line
@ -471,7 +466,7 @@ async function fetchThreads() {
}
function getMainThread() {
return currentThreadFront().actor;
return currentThreadFront.actor;
}
async function getSourceActorBreakpointPositions(
@ -515,11 +510,11 @@ function getFrontByID(actorID: String) {
}
function timeWarp(position: ExecutionPoint) {
currentThreadFront().timeWarp(position);
currentThreadFront.timeWarp(position);
}
function fetchAncestorFramePositions(index: number) {
currentThreadFront().fetchAncestorFramePositions(index);
currentThreadFront.fetchAncestorFramePositions(index);
}
const clientCommands = {
@ -572,4 +567,4 @@ const clientCommands = {
fetchAncestorFramePositions,
};
export { setupCommands, clientCommands };
export { setupCommands, setupCommandsTopTarget, clientCommands };

View File

@ -61,6 +61,8 @@ function setupEvents(dependencies: Dependencies) {
actions = dependencies.actions;
sourceQueue.initialize(actions);
devToolsClient.mainRoot.on("processListChanged", threadListChanged);
workersListener = new WorkersListener(devToolsClient.mainRoot);
threadFrontListeners = new WeakMap();

View File

@ -7,16 +7,16 @@
import { addThreadEventListeners, attachAllTargets } from "./events";
import { features } from "../../utils/prefs";
import { sameOrigin } from "../../utils/url";
import type { DevToolsClient, TargetList, Target } from "./types";
import type { DevToolsClient, Target } from "./types";
// $FlowIgnore
const { defaultThreadOptions } = require("devtools/client/shared/thread-utils");
type Args = {
currentTarget: Target,
devToolsClient: DevToolsClient,
targets: { [string]: Target },
options: Object,
targetList: TargetList,
};
async function attachTargets(targetLists, args) {
@ -48,7 +48,7 @@ async function attachTargets(targetLists, args) {
// But workers targets are still only managed by the debugger codebase
// and so we have to attach their thread actor
if (!threadFront) {
threadFront = await targetFront.attachThread({
[, threadFront] = await targetFront.attachThread({
...defaultThreadOptions(),
...args.options,
});
@ -66,8 +66,7 @@ async function attachTargets(targetLists, args) {
}
async function listWorkerTargets(args: Args) {
const { targetList, devToolsClient } = args;
const currentTarget = targetList.targetFront;
const { currentTarget, devToolsClient } = args;
if (!currentTarget.isBrowsingContext || currentTarget.isContentProcess) {
return [];
}
@ -98,26 +97,6 @@ async function listWorkerTargets(args: Args) {
serviceWorkerRegistrations = registrations.filter(front =>
sameOrigin(front.url, currentTarget.url)
);
// Service workers associated with our target's origin need to pause until
// we attach, regardless of which process they are running in.
const origin = new URL(currentTarget.url).origin;
// Still call RootFront.listProcesses instead of using the TargetList
// as the TargetList doesn't iterate over processes in the content toolbox.
const processes = await devToolsClient.mainRoot.listProcesses();
const targets = await Promise.all(
processes
.filter(descriptor => !descriptor.isParent)
.map(descriptor => descriptor.getTarget())
);
try {
await Promise.all(
targets.map(t => t.pauseMatchingServiceWorkers({ origin }))
);
} catch (e) {
// Old servers without pauseMatchingServiceWorkers will throw.
// @backward-compatibility: remove in Firefox 75
}
}
}
@ -154,14 +133,37 @@ async function listWorkerTargets(args: Args) {
return workers;
}
async function getAllProcessTargets(args) {
const { devToolsClient } = args;
const processes = await devToolsClient.mainRoot.listProcesses();
return Promise.all(
processes
.filter(descriptor => !descriptor.isParent)
.map(descriptor => descriptor.getTarget())
);
}
async function listProcessTargets(args: Args) {
const { targetList } = args;
// First note that the TargetList will only fetch processes following the same
// rules as attachAllTargets. Only if we are attached to the ParentProcessTarget
// and if the browser toolbox fission pref is turned on.
// Also note that the ParentProcessTarget actor is considered to be a FRAME and not a PROCESS.
// But this is ok, as we expect to return only content processes here.
return targetList.getAllTargets(targetList.TYPES.PROCESS);
const { currentTarget } = args;
if (!attachAllTargets(currentTarget)) {
if (currentTarget.url && features.windowlessServiceWorkers) {
// Service workers associated with our target's origin need to pause until
// we attach, regardless of which process they are running in.
const origin = new URL(currentTarget.url).origin;
const targets = await getAllProcessTargets(args);
try {
await Promise.all(
targets.map(t => t.pauseMatchingServiceWorkers({ origin }))
);
} catch (e) {
// Old servers without pauseMatchingServiceWorkers will throw.
// @backward-compatibility: remove in Firefox 75
}
}
return [];
}
return getAllProcessTargets(args);
}
export async function updateTargets(args: Args) {

View File

@ -21,7 +21,6 @@ function makeDependencies() {
devToolsClient: (null: any),
supportsWasm: true,
currentTarget: (null: any),
targetList: (null: any),
};
}

View File

@ -194,8 +194,6 @@ export type Target = {
form: { consoleActor: any },
root: any,
navigateTo: ({ url: string }) => Promise<*>,
attach: () => Promise<*>,
attachThread: Object => Promise<ThreadFront>,
listWorkers: () => Promise<*>,
reload: () => Promise<*>,
destroy: () => void,
@ -209,7 +207,6 @@ export type Target = {
url: string,
isParentProcess: Boolean,
isServiceWorker: boolean,
targetForm: Object,
// Property installed by the debugger itself.
debuggerServiceWorkerStatus: string,
@ -265,23 +262,6 @@ export type DevToolsClient = {
type ProcessDescriptor = Object;
/**
* DevToolsClient
* @memberof firefox
* @static
*/
export type TargetList = {
watchTargets: (Array<string>, Function, Function) => void,
unwatchTargets: (Array<string>, Function, Function) => void,
getAllTargets: string => Array<Target>,
targetFront: Target,
TYPES: {
FRAME: string,
PROCESS: string,
WORKER: string,
},
};
/**
* A grip is a JSON value that refers to a specific JavaScript value in the
* debuggee. Grips appear anywhere an arbitrary value from the debuggee needs

View File

@ -55,7 +55,7 @@ add_task(async function() {
const descriptorFront = await gClient.mainRoot.getMainProcess();
const front = await descriptorFront.getTarget();
await front.attach();
const threadFront = await front.attachThread();
const [, threadFront] = await front.attachThread();
gThreadFront = threadFront;
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:mozilla");

View File

@ -39,7 +39,7 @@ async function testChromeTab() {
const target = await TargetFactory.forTab(tab);
await target.attach();
const threadFront = await target.attachThread();
const [, threadFront] = await target.attachThread();
await threadFront.resume();
const { sources } = await threadFront.getSources();
@ -108,7 +108,7 @@ async function testMainProcess() {
const target = await targetDescriptor.getTarget();
await target.attach();
const threadFront = await target.attachThread();
const [, threadFront] = await target.attachThread();
await threadFront.resume();
const { sources } = await threadFront.getSources();
ok(

View File

@ -729,7 +729,7 @@ Toolbox.prototype = {
_attachAndResumeThread: async function(target) {
const options = defaultThreadOptions();
const threadFront = await target.attachThread(options);
const [, threadFront] = await target.attachThread(options);
try {
await threadFront.resume();

View File

@ -44,7 +44,7 @@ async function testEarlyDebuggerStatement(client, tab, targetFront) {
client.off("paused", onPaused);
// Now attach and resume...
const threadFront = await targetFront.attachThread();
const [, threadFront] = await targetFront.attachThread();
await threadFront.resume();
ok(true, "Pause wasn't called before we've attached.");

View File

@ -265,7 +265,7 @@ this.removeTab = function removeTab(tab, win) {
async function attachThreadActorForTab(tab) {
const target = await TargetFactory.forTab(tab);
await target.attach();
const threadFront = await target.attachThread();
const [, threadFront] = await target.attachThread();
await threadFront.resume();
return { client: target.client, threadFront };
}

View File

@ -113,7 +113,7 @@ Once the application is attached to a tab, it can attach to its thread in order
// Assuming the application is already attached to the tab, and response is the first
// argument of the attachTarget callback.
client.attachThread(response.threadActor).then(function(threadFront) {
client.attachThread(response.threadActor).then(function([response, threadFront]) {
if (!threadFront) {
return;
}
@ -178,7 +178,7 @@ function debugTab() {
// Attach to the tab.
targetFront.attach().then(() => {
// Attach to the thread (context).
targetFront.attachThread().then((threadFront) => {
targetFront.attachThread().then(([response, threadFront]) => {
// Attach listeners for thread events.
threadFront.on("paused", onPause);
threadFront.on("resumed", fooListener);

View File

@ -4,10 +4,6 @@
"use strict";
// protocol.js uses objects as exceptions in order to define
// error packets.
/* eslint-disable no-throw-literal */
const DebuggerNotificationObserver = require("DebuggerNotificationObserver");
const Services = require("Services");
const { Cr, Ci } = require("chrome");
@ -345,14 +341,14 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
// Request handlers
onAttach: function({ options }) {
if (this.state === "exited") {
throw {
return {
error: "exited",
message: "threadActor has exited",
};
}
if (this.state !== "detached") {
throw {
return {
error: "wrongState",
message: "Current state is " + this.state,
};
@ -399,7 +395,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
// Put ourselves in the paused state.
const packet = this._paused();
if (!packet) {
throw {
return {
error: "notAttached",
message: "cannot attach, could not create pause packet",
};
@ -415,12 +411,12 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
// Start a nested event loop.
this._pushThreadPause();
// We already sent a response to this request via this.conn.send(),
// don't send one now. But protocol.js probably still emits a second
// empty packet.
// We already sent a response to this request, don't send one
// now
return null;
} catch (e) {
reportException("DBG-SERVER", e);
throw {
return {
error: "notAttached",
message: e.toString(),
};

View File

@ -53,7 +53,7 @@ add_task(async function test_webextension_addon_debugging_connect() {
// When running in oop mode we can explicitly attach the thread without locking
// the main process.
const threadFront = await addonTarget.attachThread();
const [, threadFront] = await addonTarget.attachThread();
ok(threadFront, "Got a threadFront for the target addon");
is(threadFront.paused, true, "The addon threadActor is paused");

View File

@ -791,7 +791,7 @@ async function setupTestFromUrl(url) {
const targetFront = findTab(tabs, "test");
await targetFront.attach();
const threadFront = await attachThread(targetFront);
const [, threadFront] = await attachThread(targetFront);
await resume(threadFront);
const sourceUrl = getFileUrl(url);

View File

@ -11,7 +11,7 @@ add_task(
threadFrontTest(async ({ threadFront, debuggee, client, targetFront }) => {
await threadFront.detach();
Assert.equal(threadFront.state, "detached");
const newThreadFront = await targetFront.attachThread({});
const [, newThreadFront] = await targetFront.attachThread({});
Assert.notEqual(threadFront, newThreadFront);
Assert.equal(newThreadFront.state, "paused");
Assert.equal(targetFront.threadFront, newThreadFront);

View File

@ -38,7 +38,7 @@ add_task(async function() {
// Even though we have no tabs, getMainProcess gives us the chrome debugger.
const targetDescriptor = await client.mainRoot.getMainProcess();
const front = await targetDescriptor.getTarget();
const threadFront = await front.attachThread();
const [, threadFront] = await front.attachThread();
// tell the thread to do the initial resume. This would cause the
// xpcshell test harness to resume and load the file under test.

View File

@ -104,7 +104,8 @@ class BrowsingContextTargetFront extends TargetMixin(
const response = await super.attach();
this.targetForm.threadActor = response.threadActor;
this._threadActor = response.threadActor;
this.targetForm.threadActor = this._threadActor;
this.configureOptions.javascriptEnabled = response.javascriptEnabled;
this.traits = response.traits || {};

View File

@ -27,6 +27,9 @@ class ContentProcessTargetFront extends TargetMixin(
// Save the full form for Target class usage.
// Do not use `form` name to avoid colliding with protocol.js's `form` method
this.targetForm = json;
// This `_threadActor` will be used by TargetMixin.attachThread function.
this._threadActor = json.threadActor;
this.targetForm.contextActor = this._threadActor;
}
get name() {

View File

@ -348,20 +348,20 @@ function TargetMixin(parentClass) {
/**
* Attach to thread actor.
*
* This depends on having the sub-class to set the thread actor ID in `targetForm`.
* This depends on having the sub-class to set the thread actor ID in `_threadActor`.
*
* @param object options
* Configuration options.
*/
async attachThread(options = {}) {
if (!this.targetForm || !this.targetForm.threadActor) {
if (!this._threadActor) {
throw new Error(
"TargetMixin sub class should set targetForm.threadActor before calling " +
"TargetMixin sub class should set _threadActor before calling " +
"attachThread"
);
}
this.threadFront = await this.getFront("thread");
await this.threadFront.attach(options);
const result = await this.threadFront.attach(options);
this.threadFront.on("newSource", this._onNewSource);
@ -369,7 +369,7 @@ function TargetMixin(parentClass) {
// wait for the thread to be attached can resume.
this._resolveOnThreadAttached();
return this.threadFront;
return [result, this.threadFront];
}
// Listener for "newSource" event fired by the thread actor

View File

@ -80,6 +80,7 @@ class WorkerTargetFront extends TargetMixin(
// Set the ThreadActor on the target form so it is accessible by getFront
this.targetForm.consoleActor = connectResponse.consoleActor;
this.targetForm.threadActor = connectResponse.threadActor;
this._threadActor = connectResponse.threadActor;
return this.attachConsole();
})();

View File

@ -207,9 +207,15 @@ class ThreadFront extends FrontClassWithSpec(threadSpec) {
* attach to the thread actor.
*/
async attach(options) {
const onPaused = this.once("paused");
await super.attach(options);
await onPaused;
let response;
try {
const onPaused = this.once("paused");
response = await super.attach(options);
await onPaused;
} catch (e) {
throw new Error(e);
}
return response;
}
/**

View File

@ -73,7 +73,7 @@ const threadSpec = generateActorSpec({
request: {
options: Arg(0, "json"),
},
response: {},
response: RetVal("nullable:json"),
},
detach: {
request: {},

View File

@ -83,7 +83,7 @@ var _attachConsole = async function(listeners, attachToTab, attachToWorker) {
// Attach the Target and the target thread in order to instantiate the console client.
await target.attach();
const threadFront = await target.attachThread();
const [, threadFront] = await target.attachThread();
await threadFront.resume();
const webConsoleFront = await target.getFront("console");