Bug 1448287 - Fix devtools.dump.emit when using new event emitter r=jdescottes

components.stack is not always available, throw new Error() to obtain a stack instead.

MozReview-Commit-ID: BZq7zLKgA9H

--HG--
extra : rebase_source : 03878a50b4aa419830533f024c27c2df64f97265
This commit is contained in:
Mike Ratcliffe 2018-03-23 15:34:22 +00:00
Родитель 95b2b21737
Коммит e876bc8d02
5 изменённых файлов: 114 добавлений и 40 удалений

Просмотреть файл

@ -18,18 +18,22 @@ function callFunctionWithAsyncStack(callee, stack, id) {
}
/**
* Return a description of the Nth caller, suitable for logging.
* Return the Nth path from the stack excluding substr.
*
* @param {Number} n the caller to describe
* @return {String} a description of the nth caller.
* @param {Number}
* n the Nth path from the stack to describe.
* @param {String} substr
* A segment of the path that should be excluded.
*/
function describeNthCaller(n) {
function getNthPathExcluding(n, substr) {
if (isWorker) {
return "";
}
let stack = new Error().stack.split("\n");
// Add one here to skip this function.
stack = stack.filter(line => {
return line && !line.includes(substr);
});
return stack[n + 1];
}
@ -45,5 +49,5 @@ function getStack() {
}
exports.callFunctionWithAsyncStack = callFunctionWithAsyncStack;
exports.describeNthCaller = describeNthCaller;
exports.getNthPathExcluding = getNthPathExcluding;
exports.getStack = getStack;

Просмотреть файл

@ -11,11 +11,11 @@ const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {}
const {
callFunctionWithAsyncStack,
getStack,
describeNthCaller
getNthPathExcluding
} = require("devtools/client/shared/webpack/shims/platform-stack-stub");
function f3() {
return describeNthCaller(2);
return getNthPathExcluding(2);
}
function f2() {

Просмотреть файл

@ -262,7 +262,7 @@ const isEventHandler = (listener) =>
listener && handler in listener && typeof listener[handler] === "function";
const Services = require("Services");
const { describeNthCaller } = require("devtools/shared/platform/stack");
const { getNthPathExcluding } = require("devtools/shared/platform/stack");
let loggingEnabled = false;
if (!isWorker) {
@ -275,20 +275,80 @@ if (!isWorker) {
}
function serialize(target) {
let out = String(target);
const MAXLEN = 60;
// Undefined
if (typeof target === "undefined") {
return "undefined";
}
if (target === null) {
return "null";
}
// Number / String
if (typeof target === "string" ||
typeof target === "number") {
return truncate(target, MAXLEN);
}
// HTML Node
if (target.nodeName) {
let out = target.nodeName;
if (target && target.nodeName) {
out += " (" + target.nodeName;
if (target.id) {
out += "#" + target.id;
}
if (target.className) {
out += "." + target.className;
}
out += ")";
return out;
}
return out;
// Array
if (Array.isArray(target)) {
return truncate(target.toSource(), MAXLEN);
}
// Function
if (typeof target === "function") {
return `function ${target.name ? target.name : "anonymous"}()`;
}
// Window
if (target.constructor &&
target.constructor.name &&
target.constructor.name === "Window") {
return `window (${target.location.origin})`;
}
// Object
if (typeof target === "object") {
let out = "{";
let entries = Object.entries(target);
for (let i = 0; i < Math.min(10, entries.length); i++) {
let [name, value] = entries[i];
if (i > 0) {
out += ", ";
}
out += `${name}: ${truncate(value, MAXLEN)}`;
}
return out + "}";
}
// Other
return truncate(target.toSource(), MAXLEN);
}
function truncate(value, maxLen) {
// We don't use value.toString() because it can throw.
let str = String(value);
return str.length > maxLen ? str.substring(0, maxLen) + "..." : str;
}
function logEvent(type, args) {
@ -297,15 +357,20 @@ function logEvent(type, args) {
}
let argsOut = "";
let description = describeNthCaller(2);
// We need this try / catch to prevent any dead object errors.
try {
argsOut = args.map(serialize).join(", ");
argsOut = `${args.map(serialize).join(", ")}`;
} catch (e) {
// Object is dead so the toolbox is most likely shutting down,
// do nothing.
}
dump(`EMITTING: emit(${type}${argsOut}) from ${description}\n`);
const path = getNthPathExcluding(0, "devtools/shared/event-emitter.js");
if (args.length > 0) {
dump(`EMITTING: emit(${type}, ${argsOut}) from ${path}\n`);
} else {
dump(`EMITTING: emit(${type}) from ${path}\n`);
}
}

Просмотреть файл

@ -6,7 +6,7 @@
const Services = require("Services");
const defer = require("devtools/shared/defer");
const { describeNthCaller } = require("devtools/shared/platform/stack");
const { getNthPathExcluding } = require("devtools/shared/platform/stack");
let loggingEnabled = false;
if (!isWorker) {
@ -150,7 +150,7 @@ EventEmitter.prototype = {
return;
}
let description = describeNthCaller(2);
let description = getNthPathExcluding(0, "devtools/shared/old-event-emitter.js");
let argOut = "(";
if (args.length === 1) {

Просмотреть файл

@ -10,31 +10,36 @@
const { Cu, components } = require("chrome");
/**
* Return a description of the Nth caller, suitable for logging.
* Return the Nth path from the stack excluding substr.
*
* @param {Number} n the caller to describe
* @return {String} a description of the nth caller.
* @param {Number}
* n the Nth path from the stack to describe.
* @param {String} substr
* A segment of the path that should be excluded.
*/
function describeNthCaller(n) {
if (isWorker) {
return "";
function getNthPathExcluding(n, substr) {
let stack = components.stack.formattedStack.split("\n");
// Remove this method from the stack
stack = stack.splice(1);
stack = stack.map(line => {
if (line.includes(" -> ")) {
return line.split(" -> ")[1];
}
return line;
});
if (substr) {
stack = stack.filter(line => {
return line && !line.includes(substr);
});
}
let caller = components.stack;
// Do one extra iteration to skip this function.
while (n >= 0) {
--n;
caller = caller.caller;
if (!stack[n]) {
n = 0;
}
let func = caller.name;
let file = caller.filename;
if (file.includes(" -> ")) {
file = caller.filename.split(/ -> /)[1];
}
let path = file + ":" + caller.lineNumber;
return func + "() -> " + path;
return (stack[n] || "");
}
/**
@ -57,5 +62,5 @@ function callFunctionWithAsyncStack(callee, stack, id) {
}
exports.callFunctionWithAsyncStack = callFunctionWithAsyncStack;
exports.describeNthCaller = describeNthCaller;
exports.getNthPathExcluding = getNthPathExcluding;
exports.getStack = getStack;