Bug 1845156 - Remove XPCOMUtils.defineLazyProxy r=arai,Gijs"

At this point, there's only one non-test use of this method in FindBarChild.sys.mjs which could be replaced with a simpler solution.

Removing this method seems to lower memory usage a bit.
https://treeherder.mozilla.org/perfherder/compare?originalProject=try&originalRevision=2dc498c7c81bd00c989cc3b69993ec1a53ff3032&newProject=try&newRevision=32669e95c9609cb07c258ca5fe964e9eb6411ade&page=1&framework=4

Differential Revision: https://phabricator.services.mozilla.com/D184403
This commit is contained in:
Gregory Pappas 2023-07-25 23:27:51 +00:00
parent d8ef20cc4f
commit ca2d7cbfc2
7 changed files with 32 additions and 325 deletions

View File

@ -381,199 +381,12 @@ export var XPCOMUtils = {
writable: false,
});
},
/**
* Defines a proxy which acts as a lazy object getter that can be passed
* around as a reference, and will only be evaluated when something in
* that object gets accessed.
*
* The evaluation can be triggered by a function call, by getting or
* setting a property, calling this as a constructor, or enumerating
* the properties of this object (e.g. during an iteration).
*
* Please note that, even after evaluated, the object given to you
* remains being the proxy object (which forwards everything to the
* real object). This is important to correctly use these objects
* in pairs of add+remove listeners, for example.
* If your use case requires access to the direct object, you can
* get it through the untrap callback.
*
* @param aObject
* The object to define the lazy getter on.
*
* You can pass null to aObject if you just want to get this
* proxy through the return value.
*
* @param aName
* The name of the getter to define on aObject.
*
* @param aInitFuncOrResource
* A function or a module that defines what this object actually
* should be when it gets evaluated. This will only ever be called once.
*
* Short-hand: If you pass a string to this parameter, it will be treated
* as the URI of a module to be imported, and aName will be used as
* the symbol to retrieve from the module.
*
* @param aStubProperties
* In this parameter, you can provide an object which contains
* properties from the original object that, when accessed, will still
* prevent the entire object from being evaluated.
*
* These can be copies or simplified versions of the original properties.
*
* One example is to provide an alternative QueryInterface implementation
* to avoid the entire object from being evaluated when it's added as an
* observer (as addObserver calls object.QueryInterface(Ci.nsIObserver)).
*
* Once the object has been evaluated, the properties from the real
* object will be used instead of the ones provided here.
*
* @param aUntrapCallback
* A function that gets called once when the object has just been evaluated.
* You can use this to do some work (e.g. setting properties) that you need
* to do on this object but that can wait until it gets evaluated.
*
* Another use case for this is to use during code development to log when
* this object gets evaluated, to make sure you're not accidentally triggering
* it earlier than expected.
*/
defineLazyProxy(
aObject,
aName,
aInitFuncOrResource,
aStubProperties,
aUntrapCallback
) {
let initFunc = aInitFuncOrResource;
if (typeof aInitFuncOrResource == "string") {
initFunc = () => ChromeUtils.import(aInitFuncOrResource)[aName];
}
let handler = new LazyProxyHandler(
aName,
initFunc,
aStubProperties,
aUntrapCallback
);
/*
* We cannot simply create a lazy getter for the underlying
* object and pass it as the target of the proxy, because
* just passing it in `new Proxy` means it would get
* evaluated. Becase of this, a full handler needs to be
* implemented (the LazyProxyHandler).
*
* So, an empty object is used as the target, and the handler
* replaces it on every call with the real object.
*/
let proxy = new Proxy({}, handler);
if (aObject) {
Object.defineProperty(aObject, aName, {
value: proxy,
enumerable: true,
writable: true,
});
}
return proxy;
},
};
XPCOMUtils.defineLazyGetter(XPCOMUtils, "_scriptloader", () => {
return Services.scriptloader;
});
/**
* LazyProxyHandler
* This class implements the handler used
* in the proxy from defineLazyProxy.
*
* This handler forwards all calls to an underlying object,
* stored as `this.realObject`, which is obtained as the returned
* value from aInitFunc, which will be called on the first time
* time that it needs to be used (with an exception in the get() trap
* for the properties provided in the `aStubProperties` parameter).
*/
class LazyProxyHandler {
constructor(aName, aInitFunc, aStubProperties, aUntrapCallback) {
this.pending = true;
this.name = aName;
this.initFuncOrResource = aInitFunc;
this.stubProperties = aStubProperties;
this.untrapCallback = aUntrapCallback;
}
getObject() {
if (this.pending) {
this.realObject = this.initFuncOrResource.call(null);
if (this.untrapCallback) {
this.untrapCallback.call(null, this.realObject);
this.untrapCallback = null;
}
this.pending = false;
this.stubProperties = null;
}
return this.realObject;
}
getPrototypeOf(target) {
return Reflect.getPrototypeOf(this.getObject());
}
setPrototypeOf(target, prototype) {
return Reflect.setPrototypeOf(this.getObject(), prototype);
}
isExtensible(target) {
return Reflect.isExtensible(this.getObject());
}
preventExtensions(target) {
return Reflect.preventExtensions(this.getObject());
}
getOwnPropertyDescriptor(target, prop) {
return Reflect.getOwnPropertyDescriptor(this.getObject(), prop);
}
defineProperty(target, prop, descriptor) {
return Reflect.defineProperty(this.getObject(), prop, descriptor);
}
has(target, prop) {
return Reflect.has(this.getObject(), prop);
}
get(target, prop, receiver) {
if (
this.pending &&
this.stubProperties &&
Object.prototype.hasOwnProperty.call(this.stubProperties, prop)
) {
return this.stubProperties[prop];
}
return Reflect.get(this.getObject(), prop, receiver);
}
set(target, prop, value, receiver) {
return Reflect.set(this.getObject(), prop, value, receiver);
}
deleteProperty(target, prop) {
return Reflect.deleteProperty(this.getObject(), prop);
}
ownKeys(target) {
return Reflect.ownKeys(this.getObject());
}
}
var XPCU_lazyPreferenceObserverQI = ChromeUtils.generateQI([
"nsIObserver",
"nsISupportsWeakReference",

View File

@ -1,113 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This file tests the method defineLazyProxy from XPCOMUtils.sys.mjs.
*/
const {XPCOMUtils} = ChromeUtils.importESModule("resource://gre/modules/XPCOMUtils.sys.mjs");
add_task(function test_lazy_proxy() {
let tmp = {};
let realObject = {
"prop1": "value1",
"prop2": "value2",
};
let evaluated = false;
let untrapCalled = false;
let lazyProxy = XPCOMUtils.defineLazyProxy(
tmp,
"myLazyProxy",
// Initiliazer function
function init() {
evaluated = true;
return realObject;
},
// Stub properties
{
"prop1": "stub"
},
// Untrap callback
function untrapCallback(obj) {
Assert.equal(obj, realObject, "The underlying object can be obtained in the untrap callback");
untrapCalled = true;
}
);
// Check that the proxy returned and the one
// defined in tmp are the same.
//
// Note: Assert.strictEqual can't be used here
// because it wants to stringify the two objects
// compared, which defeats the lazy proxy.
Assert.ok(lazyProxy === tmp.myLazyProxy, "Return value and object defined are the same");
Assert.ok(Cu.isProxy(lazyProxy), "Returned value is in fact a proxy");
// Check that just using the proxy above didn't
// trigger the lazy getter evaluation.
Assert.ok(!evaluated, "The lazy proxy hasn't been evaluated yet");
Assert.ok(!untrapCalled, "The untrap callback hasn't been called yet");
// Accessing a stubbed property returns the stub
// value and doesn't trigger evaluation.
Assert.equal(lazyProxy.prop1, "stub", "Accessing a stubbed property returns the stubbed value");
Assert.ok(!evaluated, "The access to the stubbed property above didn't evaluate the lazy proxy");
Assert.ok(!untrapCalled, "The untrap callback hasn't been called yet");
// Now the access to another property will trigger
// the evaluation, as expected.
Assert.equal(lazyProxy.prop2, "value2", "Property access is correctly forwarded to the underlying object");
Assert.ok(evaluated, "Accessing a non-stubbed property triggered the proxy evaluation");
Assert.ok(untrapCalled, "The untrap callback was called");
// The value of prop1 is now the real value and not the stub value.
Assert.equal(lazyProxy.prop1, "value1", "The value of prop1 is now the real value and not the stub one");
});
add_task(function test_module_version() {
// Test that passing a string instead of an initialization function
// makes this behave like a lazy module getter.
const TEST_FILE_URI = "resource://test/TestFile.jsm";
let underlyingObject;
Cu.unload(TEST_FILE_URI);
let lazyProxy = XPCOMUtils.defineLazyProxy(
null,
"TestFile",
TEST_FILE_URI,
null, /* no stubs */
function untrapCallback(object) {
underlyingObject = object;
}
);
Assert.ok(!Cu.isModuleLoaded(TEST_FILE_URI), "The NetUtil module was not loaded by the lazy proxy definition");
// Access the object, which will evaluate the proxy.
lazyProxy.foo = "bar";
// Module was loaded.
Assert.ok(Cu.isModuleLoaded(TEST_FILE_URI), "The NetUtil module was loaded");
let { TestFile } = ChromeUtils.import(TEST_FILE_URI, {});
// Avoids a gigantic stringification in the logs.
Assert.ok(TestFile === underlyingObject, "The module loaded is the same as the one directly obtained by ChromeUtils.import");
// Proxy correctly passed the setter to the underlying object.
Assert.equal(TestFile.foo, "bar", "Proxy correctly passed the setter to the underlying object");
delete lazyProxy.foo;
// Proxy correctly passed the delete operation to the underlying object.
Assert.ok(!TestFile.hasOwnProperty("foo"), "Proxy correctly passed the delete operation to the underlying object");
});

View File

@ -141,7 +141,6 @@ head = head_ongc.js
[test_recursive_import.js]
[test_xpcomutils.js]
[test_unload.js]
[test_lazyproxy.js]
[test_attributes.js]
[test_params.js]
[test_tearoffs.js]

View File

@ -17,23 +17,36 @@ export class FindBarChild extends JSWindowActorChild {
this._findKey = null;
XPCOMUtils.defineLazyProxy(
this,
"FindBarContent",
() => {
const { FindBarContent } = ChromeUtils.importESModule(
"resource://gre/modules/FindBarContent.sys.mjs"
);
return new FindBarContent(this);
},
{ inQuickFind: false, inPassThrough: false }
);
this.inQuickFind = false;
this.inPassThrough = false;
ChromeUtils.defineLazyGetter(this, "FindBarContent", () => {
const { FindBarContent } = ChromeUtils.importESModule(
"resource://gre/modules/FindBarContent.sys.mjs"
);
let findBarContent = new FindBarContent(this);
Object.defineProperties(this, {
inQuickFind: {
get() {
return findBarContent.inQuickFind;
},
},
inPassThrough: {
get() {
return findBarContent.inPassThrough;
},
},
});
return findBarContent;
});
}
receiveMessage(msg) {
if (msg.name == "Findbar:UpdateState") {
let { FindBarContent } = this;
FindBarContent.updateState(msg.data);
this.FindBarContent.updateState(msg.data);
}
}
@ -65,10 +78,8 @@ export class FindBarChild extends JSWindowActorChild {
}
onKeypress(event) {
let { FindBarContent } = this;
if (!FindBarContent.inPassThrough && this.eventMatchesFindShortcut(event)) {
return FindBarContent.start(event);
if (!this.inPassThrough && this.eventMatchesFindShortcut(event)) {
return this.FindBarContent.start(event);
}
// disable FAYT in about:blank to prevent FAYT opening unexpectedly.
@ -88,17 +99,17 @@ export class FindBarChild extends JSWindowActorChild {
return null;
}
if (FindBarContent.inPassThrough || FindBarContent.inQuickFind) {
return FindBarContent.onKeypress(event);
if (this.inPassThrough || this.inQuickFind) {
return this.FindBarContent.onKeypress(event);
}
if (event.charCode && this.shouldFastFind(event.target)) {
let key = String.fromCharCode(event.charCode);
if ((key == "/" || key == "'") && FindBarChild.manualFAYT) {
return FindBarContent.startQuickFind(event);
return this.FindBarContent.startQuickFind(event);
}
if (key != " " && FindBarChild.findAsYouType) {
return FindBarContent.startQuickFind(event, true);
return this.FindBarContent.startQuickFind(event, true);
}
}
return null;

View File

@ -22,7 +22,6 @@ const callExpressionDefinitions = [
/^ChromeUtils\.defineLazyGetter\((?:globalThis|this), "(\w+)"/,
/^ChromeUtils\.defineModuleGetter\((?:globalThis|this), "(\w+)"/,
/^XPCOMUtils\.defineLazyPreferenceGetter\((?:globalThis|this), "(\w+)"/,
/^XPCOMUtils\.defineLazyProxy\((?:globalThis|this), "(\w+)"/,
/^XPCOMUtils\.defineLazyScriptGetter\((?:globalThis|this), "(\w+)"/,
/^XPCOMUtils\.defineLazyServiceGetter\((?:globalThis|this), "(\w+)"/,
/^XPCOMUtils\.defineConstant\((?:globalThis|this), "(\w+)"/,

View File

@ -17,7 +17,6 @@ const callExpressionDefinitions = [
/^ChromeUtils\.defineLazyGetter\((?:globalThis|window), "(\w+)"/,
/^ChromeUtils\.defineModuleGetter\((?:globalThis|window), "(\w+)"/,
/^XPCOMUtils\.defineLazyPreferenceGetter\((?:globalThis|window), "(\w+)"/,
/^XPCOMUtils\.defineLazyProxy\((?:globalThis|window), "(\w+)"/,
/^XPCOMUtils\.defineLazyScriptGetter\((?:globalThis|window), "(\w+)"/,
/^XPCOMUtils\.defineLazyServiceGetter\((?:globalThis|window), "(\w+)"/,
/^XPCOMUtils\.defineConstant\((?:globalThis|window), "(\w+)"/,

View File

@ -30,7 +30,6 @@ const callExpressionDefinitions = [
/^ChromeUtils\.defineLazyGetter\(lazy, "(\w+)"/,
/^ChromeUtils\.defineModuleGetter\(lazy, "(\w+)"/,
/^XPCOMUtils\.defineLazyPreferenceGetter\(lazy, "(\w+)"/,
/^XPCOMUtils\.defineLazyProxy\(lazy, "(\w+)"/,
/^XPCOMUtils\.defineLazyScriptGetter\(lazy, "(\w+)"/,
/^XPCOMUtils\.defineLazyServiceGetter\(lazy, "(\w+)"/,
/^XPCOMUtils\.defineConstant\(lazy, "(\w+)"/,