Bug 1464548: Part 2b - Don't delete properties before redefining them, because deleting properties kills JIT performance. r?mccr8
MozReview-Commit-ID: IUMg59xRoIu
--- a/js/xpconnect/loader/XPCOMUtils.jsm
+++ b/js/xpconnect/loader/XPCOMUtils.jsm
@@ -87,16 +87,31 @@
* this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
*/
var EXPORTED_SYMBOLS = [ "XPCOMUtils" ];
let global = Cu.getGlobalForObject({});
+/**
+ * Redefines the given property on the given object with the given
+ * value. This can be used to redefine getter properties which do not
+ * implement setters.
+ */
+function redefine(object, prop, value) {
+ Object.defineProperty(object, prop, {
+ configurable: true,
+ enumerable: true,
+ value,
+ writable: true,
+ });
+ return value;
+}
+
var XPCOMUtils = {
/**
* Generate a QueryInterface implementation. The returned function must be
* assigned to the 'QueryInterface' property of a JS object. When invoked on
* that object, it checks if the given iid is listed in the |interfaces|
* param, and if it is, returns |this| (the object it was called on).
* If the JS object has a classInfo property it'll be returned for the
* nsIClassInfo IID, generateCI can be used to generate the classInfo
@@ -170,31 +185,25 @@ var XPCOMUtils = {
* @param aName
* The name of the getter to define on aObject.
* @param aLambda
* A function that returns what the getter should return. This will
* only ever be called once.
*/
defineLazyGetter: function XPCU_defineLazyGetter(aObject, aName, aLambda)
{
+ let redefining = false;
Object.defineProperty(aObject, aName, {
get: function () {
- // Redefine this accessor property as a data property.
- // Delete it first, to rule out "too much recursion" in case aObject is
- // a proxy whose defineProperty handler might unwittingly trigger this
- // getter again.
- delete aObject[aName];
- let value = aLambda.apply(aObject);
- Object.defineProperty(aObject, aName, {
- value,
- writable: true,
- configurable: true,
- enumerable: true
- });
- return value;
+ if (!redefining) {
+ // Make sure we don't get into an infinite recursion loop if
+ // the getter lambda does something shady.
+ redefining = true;
+ return redefine(aObject, aName, aLambda.apply(aObject));
+ }
},
configurable: true,
enumerable: true
});
},
/**
* Defines a getter on a specified object for a script. The script will not
@@ -214,22 +223,22 @@ var XPCOMUtils = {
aResource)
{
if (!Array.isArray(aNames)) {
aNames = [aNames];
}
for (let name of aNames) {
Object.defineProperty(aObject, name, {
get: function() {
- for (let n of aNames) {
- delete aObject[n];
- }
Services.scriptloader.loadSubScript(aResource, aObject);
return aObject[name];
},
+ set(value) {
+ redefine(aObject, name, value);
+ },
configurable: true,
enumerable: true
});
}
},
/**
* Defines a getter property on the given object for each of the given