Bug 1060046 - e10s EventTarget shim broken because interpositions don't delegate properly (r=mconley)
authorBill McCloskey <wmccloskey@mozilla.com>
Mon, 15 Sep 2014 16:42:26 -0700
changeset 205416 68b381faa3781b429d44d0cff42755d3554e6c87
parent 205415 dac91d4a335cfced5cca8df9e9f66e85a293d227
child 205417 c52ad7a7c3dd525a9fc367f8e97801e3069a55b8
push id27492
push usernigelbabu@gmail.com
push dateTue, 16 Sep 2014 03:01:01 +0000
treeherdermozilla-central@4e8c6c5c0961 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1060046
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1060046 - e10s EventTarget shim broken because interpositions don't delegate properly (r=mconley)
toolkit/components/addoncompat/RemoteAddonsParent.jsm
toolkit/components/addoncompat/multiprocessShims.js
--- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm
+++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm
@@ -81,26 +81,27 @@ let NotificationTracker = {
   }
 };
 NotificationTracker.init();
 
 // An interposition is an object with three properties: methods,
 // getters, and setters. See multiprocessShims.js for an explanation
 // of how these are used. The constructor here just allows one
 // interposition to inherit members from another.
-function Interposition(base)
+function Interposition(name, base)
 {
+  this.name = name;
   if (base) {
     this.methods = Object.create(base.methods);
     this.getters = Object.create(base.getters);
     this.setters = Object.create(base.setters);
   } else {
-    this.methods = {};
-    this.getters = {};
-    this.setters = {};
+    this.methods = Object.create(null);
+    this.getters = Object.create(null);
+    this.setters = Object.create(null);
   }
 }
 
 // This object is responsible for notifying the child when a new
 // content policy is added or removed. It also runs all the registered
 // add-on content policies when the child asks it to do so.
 let ContentPolicyParent = {
   init: function() {
@@ -152,17 +153,17 @@ let ContentPolicyParent = {
 
     return Ci.nsIContentPolicy.ACCEPT;
   },
 };
 ContentPolicyParent.init();
 
 // This interposition intercepts calls to add or remove new content
 // policies and forwards these requests to ContentPolicyParent.
-let CategoryManagerInterposition = new Interposition();
+let CategoryManagerInterposition = new Interposition("CategoryManagerInterposition");
 
 CategoryManagerInterposition.methods.addCategoryEntry =
   function(addon, target, category, entry, value, persist, replace) {
     if (category == "content-policy") {
       ContentPolicyParent.addContentPolicy(entry);
     }
 
     target.addCategoryEntry(category, entry, value, persist, replace);
@@ -243,17 +244,17 @@ let AboutProtocolParent = {
       };
     } catch (e) {
       Cu.reportError(e);
     }
   },
 };
 AboutProtocolParent.init();
 
-let ComponentRegistrarInterposition = new Interposition();
+let ComponentRegistrarInterposition = new Interposition("ComponentRegistrarInterposition");
 
 ComponentRegistrarInterposition.methods.registerFactory =
   function(addon, target, class_, className, contractID, factory) {
     if (contractID.startsWith("@mozilla.org/network/protocol/about;1?")) {
       AboutProtocolParent.registerFactory(class_, className, contractID, factory);
     }
 
     target.registerFactory(class_, className, contractID, factory);
@@ -314,17 +315,17 @@ let ObserverParent = {
 ObserverParent.init();
 
 // We only forward observers for these topics.
 let TOPIC_WHITELIST = ["content-document-global-created",
                        "document-element-inserted",];
 
 // This interposition listens for
 // nsIObserverService.{add,remove}Observer.
-let ObserverInterposition = new Interposition();
+let ObserverInterposition = new Interposition("ObserverInterposition");
 
 ObserverInterposition.methods.addObserver =
   function(addon, target, observer, topic, ownsWeak) {
     if (TOPIC_WHITELIST.indexOf(topic) >= 0) {
       ObserverParent.addObserver(observer, topic);
     }
 
     target.addObserver(observer, topic, ownsWeak);
@@ -452,17 +453,17 @@ let EventTargetParent = {
       case "Addons:Event:Run":
         this.dispatch(msg.target, msg.data.type, msg.data.isTrusted, msg.objects.event);
         break;
     }
   },
 
   dispatch: function(browser, type, isTrusted, event) {
     let targets = this.getTargets(browser);
-    for (target of targets) {
+    for (let target of targets) {
       let listeners = this._listeners.get(target);
       if (!listeners) {
         continue;
       }
       let forType = setDefault(listeners, type, []);
       for (let {listener, wantsUntrusted} of forType) {
         if (wantsUntrusted || isTrusted) {
           try {
@@ -478,17 +479,17 @@ let EventTargetParent = {
       }
     }
   }
 };
 EventTargetParent.init();
 
 // This interposition redirects addEventListener and
 // removeEventListener to EventTargetParent.
-let EventTargetInterposition = new Interposition();
+let EventTargetInterposition = new Interposition("EventTargetInterposition");
 
 EventTargetInterposition.methods.addEventListener =
   function(addon, target, type, listener, useCapture, wantsUntrusted) {
     EventTargetParent.addEventListener(target, type, listener, useCapture, wantsUntrusted);
     target.addEventListener(type, listener, useCapture, wantsUntrusted);
   };
 
 EventTargetInterposition.methods.removeEventListener =
@@ -496,17 +497,17 @@ EventTargetInterposition.methods.removeE
     EventTargetParent.removeEventListener(target, type, listener, useCapture);
     target.removeEventListener(type, listener, useCapture);
   };
 
 // This interposition intercepts accesses to |rootTreeItem| on a child
 // process docshell. In the child, each docshell is its own
 // root. However, add-ons expect the root to be the chrome docshell,
 // so we make that happen here.
-let ContentDocShellTreeItemInterposition = new Interposition();
+let ContentDocShellTreeItemInterposition = new Interposition("ContentDocShellTreeItemInterposition");
 
 ContentDocShellTreeItemInterposition.getters.rootTreeItem =
   function(addon, target) {
     // The chrome global in the child.
     let chromeGlobal = target.rootTreeItem
       .QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIContentFrameMessageManager);
 
@@ -564,17 +565,17 @@ let SandboxParent = {
     let cu = this.componentsMap.get(sandbox);
     return cu.evalInSandbox(code, sandbox, ...rest);
   }
 };
 
 // This interposition redirects calls to Cu.Sandbox and
 // Cu.evalInSandbox to SandboxParent if the principals are content
 // principals.
-let ComponentsUtilsInterposition = new Interposition();
+let ComponentsUtilsInterposition = new Interposition("ComponentsUtilsInterposition");
 
 ComponentsUtilsInterposition.methods.Sandbox =
   function(addon, target, principal, ...rest) {
     if (principal &&
         typeof(principal) == "object" &&
         Cu.isCrossProcessWrapper(principal) &&
         principal instanceof Ci.nsIDOMWindow) {
       return SandboxParent.makeContentSandbox(principal, ...rest);
@@ -591,17 +592,17 @@ ComponentsUtilsInterposition.methods.eva
       return Components.utils.evalInSandbox(code, sandbox, ...rest);
     }
   };
 
 // This interposition handles cases where an add-on tries to import a
 // chrome XUL node into a content document. It doesn't actually do the
 // import, which we can't support. It just avoids throwing an
 // exception.
-let ContentDocumentInterposition = new Interposition();
+let ContentDocumentInterposition = new Interposition("ContentDocumentInterposition");
 
 ContentDocumentInterposition.methods.importNode =
   function(addon, target, node, deep) {
     if (!Cu.isCrossProcessWrapper(node)) {
       // Trying to import a node from the parent process into the
       // child process. We don't support this now. Video Download
       // Helper does this in domhook-service.js to add a XUL
       // popupmenu to content.
@@ -609,17 +610,18 @@ ContentDocumentInterposition.methods.imp
       return node;
     }
 
     return target.importNode(node, deep);
   };
 
 // This interposition ensures that calling browser.docShell from an
 // add-on returns a CPOW around the dochell.
-let RemoteBrowserElementInterposition = new Interposition(EventTargetInterposition);
+let RemoteBrowserElementInterposition = new Interposition("RemoteBrowserElementInterposition",
+                                                          EventTargetInterposition);
 
 RemoteBrowserElementInterposition.getters.docShell = function(addon, target) {
   let remoteChromeGlobal = RemoteAddonsParent.browserToGlobal.get(target);
   if (!remoteChromeGlobal) {
     // We may not have any messages from this tab yet.
     return null;
   }
   return remoteChromeGlobal.docShell;
@@ -628,17 +630,18 @@ RemoteBrowserElementInterposition.getter
 RemoteBrowserElementInterposition.getters.contentWindow = function(addon, target) {
   return target.contentWindowAsCPOW;
 };
 
 RemoteBrowserElementInterposition.getters.contentDocument = function(addon, target) {
   return target.contentDocumentAsCPOW;
 };
 
-let ChromeWindowInterposition = new Interposition(EventTargetInterposition);
+let ChromeWindowInterposition = new Interposition("ChromeWindowInterposition",
+                                                  EventTargetInterposition);
 
 ChromeWindowInterposition.getters.content = function(addon, target) {
   return target.gBrowser.selectedBrowser.contentWindowAsCPOW;
 };
 
 let RemoteAddonsParent = {
   init: function() {
     let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
--- a/toolkit/components/addoncompat/multiprocessShims.js
+++ b/toolkit/components/addoncompat/multiprocessShims.js
@@ -114,28 +114,27 @@ AddonInterpositionService.prototype = {
     }
 
     if (!interp) {
       return null;
     }
 
     let desc = { configurable: false, enumerable: true };
 
-    if ("methods" in interp && interp.methods.hasOwnProperty(prop)) {
+    if ("methods" in interp && prop in interp.methods) {
       desc.writable = false;
       desc.value = function(...args) {
         return interp.methods[prop](addon, target, ...args);
       }
 
       return desc;
-    } else if ("getters" in interp &&
-               interp.getters.hasOwnProperty(prop)) {
+    } else if ("getters" in interp && prop in interp.getters) {
       desc.get = function() { return interp.getters[prop](addon, target); };
 
-      if ("setters" in interp && interp.setters.hasOwnProperty(prop)) {
+      if ("setters" in interp && prop in interp.setters) {
         desc.set = function(v) { return interp.setters[prop](addon, target, v); };
       }
 
       return desc;
     }
 
     return null;
   },