Skip to content
Snippets Groups Projects
Commit 5be4d4d4 authored by Alexandre Poirot's avatar Alexandre Poirot
Browse files

Bug 1825339 - [devtools] Speed up makeDebuggeeValue. r=devtools-reviewers,nchevobbe

This method could early return for all primitive types as they already are "debuggee values".
Then, when we have non primitives, getGlobalForObject should work
and reliably return the value's global.
The global is needed as Debugger.Object's makeDebuggeeValue only works
for objects of the same global.

There is just this edgecase around object coming from globals which
are flagged as "invisible to debugger".
We might want to return a special debuggee value instead of trying
to instantiate this special Debugger.Object which mostly throws...

I've also updated and added meaningful comments to clarify all this code.

Differential Revision: https://phabricator.services.mozilla.com/D174040
parent 6084f90f
No related branches found
No related tags found
No related merge requests found
......@@ -65,14 +65,20 @@ function getPromiseState(obj) {
}
/**
* Returns true if value is an object or function
* Returns true if value is an object or function.
*
* @param value
* @returns {boolean}
*/
function isObjectOrFunction(value) {
return value && (typeof value == "object" || typeof value == "function");
// Handle null, whose typeof is object
if (!value) {
return false;
}
const type = typeof value;
return type == "object" || type == "function";
}
/**
......@@ -425,24 +431,45 @@ function getModifiersForEvent(rawObj) {
* Debuggee value for |value|.
*/
function makeDebuggeeValue(targetActor, value) {
if (isObject(value)) {
try {
const global = Cu.getGlobalForObject(value);
const dbgGlobal = targetActor.dbg.makeGlobalObjectReference(global);
return dbgGlobal.makeDebuggeeValue(value);
} catch (ex) {
// The above can throw an exception if value is not an actual object
// or 'Object in compartment marked as invisible to Debugger'
// Primitive types are debuggee values and Debugger.Object.makeDebuggeeValue
// would return them unchanged. So avoid the expense of:
// getGlobalForObject+makeGlobalObjectReference+makeDebugeeValue for them.
//
// It is actually easier to identify non primitive which can only be object or function.
if (!isObjectOrFunction(value)) {
return value;
}
// `value` may come from various globals.
// And Debugger.Object.makeDebuggeeValue only works for objects
// related to the same global. So fetch the global first,
// in order to instantiate a Debugger.Object for it.
//
// In the worker thread, we don't have access to Cu,
// but at the same time, there is only one global, the worker one.
const valueGlobal = isWorker ? targetActor.workerGlobal : Cu.getGlobalForObject(value);
let dbgGlobal;
try {
dbgGlobal = targetActor.dbg.makeGlobalObjectReference(
valueGlobal
);
} catch(e) {
// makeGlobalObjectReference will throw if the global is invisible to Debugger,
// in this case instantiate a Debugger.Object for the top level global
// of the target. Even if value will come from another global, it will "work",
// but the Debugger.Object created via dbgGlobal.makeDebuggeeValue will throw
// on most methods as the object will also be invisible to Debuggee...
if (e.message.includes("object in compartment marked as invisible to Debugger")) {
dbgGlobal = targetActor.dbg.makeGlobalObjectReference(
targetActor.window
);
} else {
throw e;
}
}
const dbgGlobal = targetActor.dbg.makeGlobalObjectReference(
targetActor.window || targetActor.workerGlobal
);
return dbgGlobal.makeDebuggeeValue(value);
}
function isObject(value) {
return Object(value) === value;
return dbgGlobal.makeDebuggeeValue(value);
}
/**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment