Files
palemoon27/toolkit/devtools/shared/worker.js
T
roytam1 7529dc68e8 import changes from `dev' branch of rmottola/Arctic-Fox:
- import VMX Blur from TenFourFox and adapt moz.build with HAVE_ALTIVEC (f23006226)
- Bug 1176083. Remove the now-dead code for the XPCOM version of setTimeout/setInterval. r=smaug (af84a61a6)
- Bug 1148593 - Pass JSContext to CallbackObject constructor. r=bz (548cda0cc)
- Bug 1164564 - Clean up the worker loader;r=jlong (c22a9241c)
- Bug 1164564 - Refactor Promise-backend.js so it can be required as a CommonJS module;r=jlong (6ced4a7f2)
- Bug 1084525 - Part 4: Add listPromises method to PromisesActor r=fitzgen (132c6b062)
- Bug 1084525 - Part 5: Add onNewPromise event handler to PromisesActor r=fitzgen (07098d58c)
- Bug 1084525 - Part 6: Add onPromiseSettled event handler to PromisesActor r=fitzgen (11d0c7430)
- Bug 1164483 - move worker helpers from frontend of devtools to backend r=jsantell (d5a0d16af)
- Bug 1164632 - use new worker helpers in debugger for pretty-printing r=jsantell (de356582a)
- do not run a test program to see if -maltivec is supported, since GCC always accepts it, even if an incompatible processor is selected. Offer explicit enable-altivec option and also set CXXFLAGS (c78bc8e43)
- extend removing of optimizations to all newer GCC versions, since it is a code issue, not compiler one (29639f4d5)
2021-04-19 11:02:56 +08:00

169 lines
5.5 KiB
JavaScript

/* 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";
(function (factory) { // Module boilerplate
if (this.module && module.id.indexOf("worker") >= 0) { // require
const { Cc, Ci, Cu, ChromeWorker } = require("chrome");
const dumpn = require("devtools/toolkit/DevToolsUtils").dumpn;
factory.call(this, require, exports, module, { Cc, Ci, Cu }, ChromeWorker, dumpn);
} else { // Cu.import
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
this.isWorker = false;
this.Promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
this.console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
factory.call(
this, devtools.require, this, { exports: this },
{ Cc, Ci, Cu }, ChromeWorker, null
);
this.EXPORTED_SYMBOLS = ["DevToolsWorker"];
}
}).call(this, function (require, exports, module, { Ci, Cc }, ChromeWorker, dumpn) {
let MESSAGE_COUNTER = 0;
/**
* Creates a wrapper around a ChromeWorker, providing easy
* communication to offload demanding tasks. The corresponding URL
* must implement the interface provided by `devtools/toolkit/shared/worker-helper`.
*
* @see `./toolkit/devtools/shared/widgets/GraphsWorker.js`
*
* @param {string} url
* The URL of the worker.
* @param Object opts
* An option with the following optional fields:
* - name: a name that will be printed with logs
* - verbose: log incoming and outgoing messages
*/
function DevToolsWorker (url, opts) {
opts = opts || {};
this._worker = new ChromeWorker(url);
this._verbose = opts.verbose;
this._name = opts.name;
this._worker.addEventListener("error", this.onError, false);
}
exports.DevToolsWorker = DevToolsWorker;
/**
* Performs the given task in a chrome worker, passing in data.
* Returns a promise that resolves when the task is completed, resulting in
* the return value of the task.
*
* @param {string} task
* The name of the task to execute in the worker.
* @param {any} data
* Data to be passed into the task implemented by the worker.
* @return {Promise}
*/
DevToolsWorker.prototype.performTask = function (task, data) {
if (this._destroyed) {
return Promise.reject("Cannot call performTask on a destroyed DevToolsWorker");
}
let worker = this._worker;
let id = ++MESSAGE_COUNTER;
let payload = { task, id, data };
if(this._verbose && dumpn) {
dumpn("Sending message to worker" +
(this._name ? (" (" + this._name + ")") : "" ) +
": " +
JSON.stringify(payload, null, 2));
}
worker.postMessage(payload);
return new Promise((resolve, reject) => {
let listener = ({ data }) => {
if(this._verbose && dumpn) {
dumpn("Received message from worker" +
(this._name ? (" (" + this._name + ")") : "" ) +
": " +
JSON.stringify(data, null, 2));
}
if (data.id !== id) {
return;
}
worker.removeEventListener("message", listener);
if (data.error) {
reject(data.error);
} else {
resolve(data.response);
}
};
worker.addEventListener("message", listener);
});
}
/**
* Terminates the underlying worker. Use when no longer needing the worker.
*/
DevToolsWorker.prototype.destroy = function () {
this._worker.terminate();
this._worker = null;
this._destroyed = true;
};
DevToolsWorker.prototype.onError = function({ message, filename, lineno }) {
dump(new Error(message + " @ " + filename + ":" + lineno) + "\n");
}
/**
* Takes a function and returns a Worker-wrapped version of the same function.
* Returns a promise upon resolution.
* @see `./toolkit/devtools/shared/tests/browser_devtools-worker-03.js
*
* * * * ! ! ! This should only be used for tests or A/B testing performance ! ! ! * * * * * *
*
* The original function must:
*
* Be a pure function, that is, not use any variables not declared within the
* function, or its arguments.
*
* Return a value or a promise.
*
* Note any state change in the worker will not affect the callee's context.
*
* @param {function} fn
* @return {function}
*/
function workerify (fn) {
console.warn(`\`workerify\` should only be used in tests or measuring performance.
This creates an object URL on the browser window, and should not be used in production.`)
// Fetch via window/utils here as we don't want to include
// this module normally.
let { getMostRecentBrowserWindow } = require("sdk/window/utils");
let { URL, Blob } = getMostRecentBrowserWindow();
let stringifiedFn = createWorkerString(fn);
let blob = new Blob([stringifiedFn]);
let url = URL.createObjectURL(blob);
let worker = new DevToolsWorker(url);
let wrapperFn = data => worker.performTask("workerifiedTask", data);
wrapperFn.destroy = function () {
URL.revokeObjectURL(url);
worker.destroy();
};
return wrapperFn;
}
exports.workerify = workerify;
/**
* Takes a function, and stringifies it, attaching the worker-helper.js
* boilerplate hooks.
*/
function createWorkerString (fn) {
return `importScripts("resource://gre/modules/workers/require.js");
const { createTask } = require("resource://gre/modules/devtools/shared/worker-helper");
createTask(self, "workerifiedTask", ${fn.toString()});
`;
}
});