Bug 1456035: Part 5 - Convert manual QueryInterface to ChromeUtils.generateQI. r?mccr8 draft
authorKris Maglione <maglione.k@gmail.com>
Mon, 23 Apr 2018 12:58:34 -0700
changeset 786766 d8ad6581e5206c9d9d7d461ed07e3b33de08a1d2
parent 786765 69ca4d64c851c6629e89fd31aa49b6e015388dba
push id107565
push usermaglione.k@gmail.com
push dateMon, 23 Apr 2018 20:00:34 +0000
reviewersmccr8
bugs1456035
milestone61.0a1
Bug 1456035: Part 5 - Convert manual QueryInterface to ChromeUtils.generateQI. r?mccr8 Manually-implemented QueryInterface functions don't benefit from the MozQueryInterface optimizaions, and a lot of them are in hot code, and implement a large number of interfaces. MozReview-Commit-ID: 8OzglraowZt
browser/base/content/aboutDialog-appUpdater.js
browser/base/content/browser.js
browser/base/content/tabbrowser.js
browser/base/content/web-panels.js
browser/components/feeds/FeedConverter.js
browser/components/feeds/WebContentConverter.js
browser/components/nsBrowserContentHandler.js
browser/components/places/content/bookmarkProperties.js
browser/components/places/content/browserPlacesViews.js
browser/components/places/content/places.js
browser/components/preferences/in-content/main.js
devtools/client/responsive.html/browser/content.js
devtools/shared/gcli/commands/screenshot.js
dom/push/PushServiceHttp2.jsm
mobile/android/modules/Notifications.jsm
mobile/android/modules/SSLExceptions.jsm
toolkit/components/contentprefs/ContentPrefService2.js
toolkit/components/printing/content/printPreviewProgress.js
toolkit/components/printing/content/printProgress.js
toolkit/components/printing/content/printUtils.js
toolkit/components/viewsource/content/viewSourceUtils.js
toolkit/content/browser-child.js
toolkit/content/contentAreaUtils.js
toolkit/modules/CertUtils.jsm
toolkit/modules/FinderHighlighter.jsm
toolkit/modules/addons/WebRequest.jsm
toolkit/mozapps/downloads/DownloadLastDir.jsm
toolkit/mozapps/downloads/nsHelperAppDlg.js
toolkit/mozapps/extensions/amWebAPI.js
toolkit/mozapps/update/content/updates.js
--- a/browser/base/content/aboutDialog-appUpdater.js
+++ b/browser/base/content/aboutDialog-appUpdater.js
@@ -296,22 +296,17 @@ appUpdater.prototype =
       // notified with the normal app update user interface so this is safe.
       gAppUpdater.isChecking = false;
       gAppUpdater.selectPanel("noUpdatesFound");
     },
 
     /**
      * See nsISupports.idl
      */
-    QueryInterface(aIID) {
-      if (!aIID.equals(Ci.nsIUpdateCheckListener) &&
-          !aIID.equals(Ci.nsISupports))
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      return this;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIUpdateCheckListener"]),
   },
 
   /**
    * Starts the download of an update mar.
    */
   startDownload() {
     if (!this.update)
       this.update = this.um.activeUpdate;
@@ -422,16 +417,10 @@ appUpdater.prototype =
   onProgress(aRequest, aContext, aProgress, aProgressMax) {
     this.downloadStatus.textContent =
       DownloadUtils.getTransferTotal(aProgress, aProgressMax);
   },
 
   /**
    * See nsISupports.idl
    */
-  QueryInterface(aIID) {
-    if (!aIID.equals(Ci.nsIProgressEventSink) &&
-        !aIID.equals(Ci.nsIRequestObserver) &&
-        !aIID.equals(Ci.nsISupports))
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    return this;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIProgressEventSink", "nsIRequestObserver"]),
 };
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4489,25 +4489,20 @@ var XULBrowserWindow = {
   // Stored Status, Link and Loading values
   status: "",
   defaultStatus: "",
   overLink: "",
   startTime: 0,
   isBusy: false,
   busyUI: false,
 
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIWebProgressListener) ||
-        aIID.equals(Ci.nsIWebProgressListener2) ||
-        aIID.equals(Ci.nsISupportsWeakReference) ||
-        aIID.equals(Ci.nsIXULBrowserWindow) ||
-        aIID.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_NOINTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
+                                          "nsIWebProgressListener2",
+                                          "nsISupportsWeakReference",
+                                          "nsIXULBrowserWindow"]),
 
   get stopCommand() {
     delete this.stopCommand;
     return this.stopCommand = document.getElementById("Browser:Stop");
   },
   get reloadCommand() {
     delete this.reloadCommand;
     return this.reloadCommand = document.getElementById("Browser:Reload");
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -4564,26 +4564,21 @@ class TabProgressListener {
     this._callProgressListeners("onSecurityChange",
                                 [aWebProgress, aRequest, aState]);
   }
 
   onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
     return this._callProgressListeners("onRefreshAttempted",
                                        [aWebProgress, aURI, aDelay, aSameURI]);
   }
-
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIWebProgressListener) ||
-        aIID.equals(Ci.nsIWebProgressListener2) ||
-        aIID.equals(Ci.nsISupportsWeakReference) ||
-        aIID.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_NOINTERFACE;
-  }
 }
+TabProgressListener.prototype.QueryInterface = ChromeUtils.generateQI(
+  ["nsIWebProgressListener",
+   "nsIWebProgressListener2",
+   "nsISupportsWeakReference"]);
 
 var StatusPanel = {
   get panel() {
     window.addEventListener("resize", this);
 
     delete this.panel;
     return this.panel = document.getElementById("statuspanel");
   },
--- a/browser/base/content/web-panels.js
+++ b/browser/base/content/web-panels.js
@@ -42,23 +42,17 @@ var panelProgressListener = {
     },
 
     onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
     },
 
     onSecurityChange(aWebProgress, aRequest, aState) {
     },
 
-    QueryInterface(aIID) {
-        if (aIID.equals(Ci.nsIWebProgressListener) ||
-            aIID.equals(Ci.nsISupportsWeakReference) ||
-            aIID.equals(Ci.nsISupports))
-            return this;
-        throw Cr.NS_NOINTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener", "nsISupportsWeakReference"]),
 };
 
 var gLoadFired = false;
 function loadWebPanel(aURI) {
     var panelBrowser = getPanelBrowser();
     if (gLoadFired) {
         panelBrowser.webNavigation
                     .loadURI(aURI, Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
--- a/browser/components/feeds/FeedConverter.js
+++ b/browser/components/feeds/FeedConverter.js
@@ -321,25 +321,20 @@ FeedConverter.prototype = {
   onStopRequest(request, context, status) {
     if (this._processor)
       this._processor.onStopRequest(request, context, status);
   },
 
   /**
    * See nsISupports.idl
    */
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIFeedResultListener) ||
-        iid.equals(Ci.nsIStreamConverter) ||
-        iid.equals(Ci.nsIStreamListener) ||
-        iid.equals(Ci.nsIRequestObserver) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFeedResultListener",
+                                          "nsIStreamConverter",
+                                          "nsIStreamListener",
+                                          "nsIRequestObserver"]),
 };
 
 /**
  * Keeps parsed FeedResults around for use elsewhere in the UI after the stream
  * converter completes.
  */
 function FeedResultService() {
 }
@@ -451,23 +446,18 @@ FeedResultService.prototype = {
   },
 
   createInstance(outer, iid) {
     if (outer != null)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return this.QueryInterface(iid);
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIFeedResultService) ||
-        iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFeedResultService",
+                                          "nsIFactory"]),
 };
 
 
 var components = [FeedConverter,
                   FeedResultService];
 
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/browser/components/feeds/WebContentConverter.js
+++ b/browser/components/feeds/WebContentConverter.js
@@ -43,38 +43,28 @@ WebContentConverter.prototype = {
 
   onStartRequest(request, context) {
     let wccr =
         Cc[WCCR_CONTRACTID].
         getService(Ci.nsIWebContentConverterService);
     wccr.loadPreferredHandler(request);
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIStreamConverter) ||
-        iid.equals(Ci.nsIStreamListener) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIStreamConverter",
+                                          "nsIStreamListener"]),
 };
 
 let WebContentConverterFactory = {
   createInstance(outer, iid) {
     if (outer != null)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return new WebContentConverter().QueryInterface(iid);
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory"]),
 };
 
 function ServiceInfo(contentType, uri, name) {
   this._contentType = contentType;
   this._uri = uri;
   this._name = name;
 }
 ServiceInfo.prototype = {
@@ -116,22 +106,17 @@ ServiceInfo.prototype = {
 
   /**
    * See nsIWebContentHandlerInfo
    */
   getHandlerURI(uri) {
     return this._uri.replace(/%s/gi, encodeURIComponent(uri));
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIWebContentHandlerInfo) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIWebContentHandlerInfo"]),
 };
 
 const Utils = {
   makeURI(aURL, aOriginCharset, aBaseURI) {
     return Services.io.newURI(aURL, aOriginCharset, aBaseURI);
   },
 
   checkAndGetURI(aURIString, aContentWindow) {
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -692,23 +692,17 @@ function handURIToExistingBrowser(uri, l
 
 function nsDefaultCommandLineHandler() {
 }
 
 nsDefaultCommandLineHandler.prototype = {
   classID: Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}"),
 
   /* nsISupports */
-  QueryInterface: function dch_QI(iid) {
-    if (!iid.equals(Ci.nsISupports) &&
-        !iid.equals(Ci.nsICommandLineHandler))
-      throw Cr.NS_ERROR_NO_INTERFACE;
-
-    return this;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsICommandLineHandler"]),
 
   _haveProfile: false,
 
   /* nsICommandLineHandler */
   handle: function dch_handle(cmdLine) {
     var urilist = [];
 
     if (AppConstants.platform == "win") {
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -367,22 +367,17 @@ var BookmarkPropertiesPanel = {
           this._height += -oldHeight + newHeight;
           elementsHeight.set(id, newHeight);
         }
         break;
     }
   },
 
   // nsISupports
-  QueryInterface: function BPP_QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_NOINTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI([]),
 
   _element: function BPP__element(aID) {
     return document.getElementById("editBMPanel_" + aID);
   },
 
   onDialogUnload() {
     // gEditItemOverlay does not exist anymore here, so don't rely on it.
     this._mutationObserver.disconnect();
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -14,16 +14,19 @@ function PlacesViewBase(aPlace, aOptions
   if ("viewElt" in aOptions)
     this._viewElt = aOptions.viewElt;
   this.options = aOptions;
   this._controller = new PlacesController(this);
   this.place = aPlace;
   this._viewElt.controllers.appendController(this._controller);
 }
 
+PlacesViewBase.interfaces = [Ci.nsINavHistoryResultObserver,
+                             Ci.nsISupportsWeakReference];
+
 PlacesViewBase.prototype = {
   // The xul element that holds the entire view.
   _viewElt: null,
   get viewElt() {
     return this._viewElt;
   },
 
   get associatedElement() {
@@ -37,18 +40,17 @@ PlacesViewBase.prototype = {
   // The xul element that represents the root container.
   _rootElt: null,
 
   // Set to true for views that are represented by native widgets (i.e.
   // the native mac menu).
   _nativeView: false,
 
   QueryInterface: ChromeUtils.generateQI(
-    [Ci.nsINavHistoryResultObserver,
-     Ci.nsISupportsWeakReference]),
+    PlacesViewBase.interfaces),
 
   _place: "",
   get place() {
     return this._place;
   },
   set place(val) {
     this._place = val;
 
@@ -1003,22 +1005,18 @@ function PlacesToolbar(aPlace) {
 }
 
 PlacesToolbar.prototype = {
   __proto__: PlacesViewBase.prototype,
 
   _cbEvents: ["dragstart", "dragover", "dragexit", "dragend", "drop",
               "mousemove", "mouseover", "mouseout"],
 
-  QueryInterface: function PT_QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsITimerCallback))
-      return this;
-
-    return PlacesViewBase.prototype.QueryInterface.apply(this, arguments);
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsITimerCallback",
+                                          ...PlacesViewBase.interfaces]),
 
   uninit: function PT_uninit() {
     this._removeEventListeners(this._viewElt, this._cbEvents, false);
     this._removeEventListeners(this._rootElt, ["popupshowing", "popuphidden"],
                                true);
     this._removeEventListeners(this._rootElt, ["overflow", "underflow"], true);
     this._removeEventListeners(window, ["resize", "unload"], false);
     this._removeEventListeners(gBrowser.tabContainer, ["TabOpen", "TabClose"], false);
@@ -1966,20 +1964,16 @@ function PlacesPanelMenuView(aPlace, aVi
   this.options = aOptions;
 
   PlacesViewBase.call(this, aPlace, aOptions);
 }
 
 PlacesPanelMenuView.prototype = {
   __proto__: PlacesViewBase.prototype,
 
-  QueryInterface: function PAMV_QueryInterface(aIID) {
-    return PlacesViewBase.prototype.QueryInterface.apply(this, arguments);
-  },
-
   uninit: function PAMV_uninit() {
     PlacesViewBase.prototype.uninit.apply(this, arguments);
   },
 
   _insertNewItem:
   function PAMV__insertNewItem(aChild, aInsertionNode, aBefore = null) {
     this._domNodes.delete(aChild);
 
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -191,22 +191,17 @@ var PlacesOrganizer = {
 
     if (!Services.policies.isAllowed("profileImport")) {
       document.getElementById("OrganizerCommand_browserImport").setAttribute("disabled", true);
     }
 
     ContentArea.focus();
   },
 
-  QueryInterface: function PO_QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_NOINTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI([]),
 
   handleEvent: function PO_handleEvent(aEvent) {
     if (aEvent.type != "AppCommand")
       return;
 
     aEvent.stopPropagation();
     switch (aEvent.command) {
       case "Back":
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -3000,24 +3000,17 @@ FeedHandlerInfo.prototype = {
       return this._possibleApplicationHandlers;
 
     // A minimal implementation of nsIMutableArray.  It only supports the two
     // methods its callers invoke, namely appendElement and nsIArray::enumerate.
     this._possibleApplicationHandlers = {
       _inner: [],
       _removed: [],
 
-      QueryInterface(aIID) {
-        if (aIID.equals(Ci.nsIMutableArray) ||
-          aIID.equals(Ci.nsIArray) ||
-          aIID.equals(Ci.nsISupports))
-          return this;
-
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      },
+      QueryInterface: ChromeUtils.generateQI(["nsIMutableArray", "nsIArray"]),
 
       get length() {
         return this._inner.length;
       },
 
       enumerate() {
         return new ArrayEnumerator(this._inner);
       },
--- a/devtools/client/responsive.html/browser/content.js
+++ b/devtools/client/responsive.html/browser/content.js
@@ -178,21 +178,15 @@ var global = this;
 
   let WebProgressListener = {
     onLocationChange(webProgress, request, URI, flags) {
       if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
         return;
       }
       makeScrollbarsFloating();
     },
-    QueryInterface: function QueryInterface(iid) {
-      if (iid.equals(Ci.nsIWebProgressListener) ||
-          iid.equals(Ci.nsISupportsWeakReference) ||
-          iid.equals(Ci.nsISupports)) {
-        return this;
-      }
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
+                                            "nsISupportsWeakReference"]),
   };
 })();
 
 global.responsiveFrameScriptLoaded = true;
 sendAsyncMessage("ResponsiveMode:ChildScriptReady");
--- a/devtools/shared/gcli/commands/screenshot.js
+++ b/devtools/shared/gcli/commands/screenshot.js
@@ -486,25 +486,19 @@ function DownloadListener(win, transfer)
   }
 
   // Allow saveToFile to await completion for error handling
   this._completedDeferred = defer();
   this.completed = this._completedDeferred.promise;
 }
 
 DownloadListener.prototype = {
-  QueryInterface: function(iid) {
-    if (iid.equals(Ci.nsIInterfaceRequestor) ||
-        iid.equals(Ci.nsIWebProgressListener) ||
-        iid.equals(Ci.nsIWebProgressListener2) ||
-        iid.equals(Ci.nsISupports)) {
-      return this;
-    }
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIInterfaceRequestor",
+                                          "nsIWebProgressListener",
+                                          "nsIWebProgressListener2"]),
 
   getInterface: function(iid) {
     if (iid.equals(Ci.nsIAuthPrompt) ||
         iid.equals(Ci.nsIAuthPrompt2)) {
       let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]
                  .getService(Ci.nsIPromptFactory);
       return ww.getPrompt(this.window, iid);
     }
--- a/dom/push/PushServiceHttp2.jsm
+++ b/dom/push/PushServiceHttp2.jsm
@@ -45,23 +45,18 @@ const kPUSHHTTP2DB_STORE_NAME = "pushHtt
 var PushSubscriptionListener = function(pushService, uri) {
   console.debug("PushSubscriptionListener()");
   this._pushService = pushService;
   this.uri = uri;
 };
 
 PushSubscriptionListener.prototype = {
 
-  QueryInterface: function (aIID) {
-    if (aIID.equals(Ci.nsIHttpPushListener) ||
-        aIID.equals(Ci.nsIStreamListener)) {
-      return this;
-    }
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIHttpPushListener",
+                                         "nsIStreamListener"]),
 
   getInterface: function(aIID) {
     return this.QueryInterface(aIID);
   },
 
   onStartRequest: function(aRequest, aContext) {
     console.debug("PushSubscriptionListener: onStartRequest()");
     // We do not do anything here.
--- a/mobile/android/modules/Notifications.jsm
+++ b/mobile/android/modules/Notifications.jsm
@@ -231,18 +231,13 @@ var Notifications = {
 
         if (notification && notification._onCancel)
           notification._onCancel(id, notification._cookie);
         delete _notificationsMap[id]; // since the notification was dismissed, we no longer need to hold a reference.
         break;
     }
   },
 
-  QueryInterface: function(aIID) {
-    if (!aIID.equals(Ci.nsISupports) &&
-        !aIID.equals(Ci.nsIObserver) &&
-        !aIID.equals(Ci.nsISupportsWeakReference))
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    return this;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIObserver",
+                                          "nsISupportsWeakReference"]),
 };
 
 EventDispatcher.instance.registerListener(Notifications, "Notification:Event");
--- a/mobile/android/modules/SSLExceptions.jsm
+++ b/mobile/android/modules/SSLExceptions.jsm
@@ -21,23 +21,17 @@ function SSLExceptions() {
 
 SSLExceptions.prototype = {
   _overrideService: null,
   _sslStatus: null,
 
   getInterface: function SSLE_getInterface(aIID) {
     return this.QueryInterface(aIID);
   },
-  QueryInterface: function SSLE_QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIBadCertListener2) ||
-        aIID.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIBadCertListener2"]),
 
   /**
     To collect the SSL status we intercept the certificate error here
     and store the status for later use.
   */
   notifyCertProblem: function SSLE_notifyCertProblem(socketInfo, sslStatus, targetHost) {
     this._sslStatus = sslStatus.QueryInterface(Ci.nsISSLStatus);
     return true; // suppress error UI
--- a/toolkit/components/contentprefs/ContentPrefService2.js
+++ b/toolkit/components/contentprefs/ContentPrefService2.js
@@ -950,26 +950,18 @@ ContentPrefService2.prototype = {
     this._observers = {};
     this._genericObservers = [];
 
     let tables = ["prefs", "groups", "settings"];
     let stmts = tables.map(t => this._stmt(`DELETE FROM ${t}`));
     this._execStmts(stmts, { onDone: () => callback() });
   },
 
-  QueryInterface: function CPS2_QueryInterface(iid) {
-    let supportedIIDs = [
-      Ci.nsIContentPrefService2,
-      Ci.nsIObserver,
-      Ci.nsISupports,
-    ];
-    if (supportedIIDs.some(i => iid.equals(i)))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIContentPrefService2",
+                                          "nsIObserver"]),
 
 
   // Database Creation & Access
 
   _dbVersion: 4,
 
   _dbSchema: {
     tables: {
--- a/toolkit/components/printing/content/printPreviewProgress.js
+++ b/toolkit/components/printing/content/printPreviewProgress.js
@@ -61,21 +61,18 @@ var progressListener = {
   onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {},
   onSecurityChange(aWebProgress, aRequest, state) {},
 
   onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
     if (aMessage)
       dialog.title.setAttribute("value", aMessage);
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIWebProgressListener) || iid.equals(Ci.nsISupportsWeakReference))
-      return this;
-    throw Cr.NS_NOINTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
+                                          "nsISupportsWeakReference"]),
 };
 
 function onLoad() {
   // Set global variables.
   printProgress = window.arguments[0];
   if (window.arguments[1]) {
     progressParams = window.arguments[1].QueryInterface(Ci.nsIPrintProgressParams);
     if (progressParams) {
--- a/toolkit/components/printing/content/printProgress.js
+++ b/toolkit/components/printing/content/printProgress.js
@@ -143,22 +143,18 @@ var progressListener = {
       if (aMessage != "")
         dialog.title.setAttribute("value", aMessage);
     },
 
     onSecurityChange(aWebProgress, aRequest, state) {
       // we can ignore this notification
     },
 
-    QueryInterface(iid) {
-     if (iid.equals(Ci.nsIWebProgressListener) || iid.equals(Ci.nsISupportsWeakReference))
-      return this;
-
-     throw Cr.NS_NOINTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
+                                            "nsISupportsWeakReference"]),
 };
 
 function getString( stringId ) {
    // Check if we've fetched this string already.
    if (!(stringId in dialog.strings)) {
       // Try to get it.
       var elem = document.getElementById( "dialog.strings." + stringId );
       try {
--- a/toolkit/components/printing/content/printUtils.js
+++ b/toolkit/components/printing/content/printUtils.js
@@ -394,23 +394,18 @@ var PrintUtils = {
       if (aTopic) {
         return;
       }
 
       // delay the print preview to show the content of the progress dialog
       setTimeout(function() { PrintUtils.enterPrintPreview(); }, 0);
     },
 
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsIObserver) ||
-          iid.equals(Ci.nsISupportsWeakReference) ||
-          iid.equals(Ci.nsISupports))
-        return this;
-      throw Cr.NS_NOINTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIObserver",
+                                            "nsISupportsWeakReference"]),
   },
 
   setSimplifiedMode(shouldSimplify) {
     this._shouldSimplify = shouldSimplify;
   },
 
   /**
   * Currently, we create a new print preview browser to host the simplified
--- a/toolkit/components/viewsource/content/viewSourceUtils.js
+++ b/toolkit/components/viewsource/content/viewSourceUtils.js
@@ -265,23 +265,18 @@ var gViewSourceUtils = {
 
     return null;
   },
 
   viewSourceProgressListener: {
 
     mnsIWebProgressListener: Ci.nsIWebProgressListener,
 
-    QueryInterface(aIID) {
-     if (aIID.equals(this.mnsIWebProgressListener) ||
-         aIID.equals(Ci.nsISupportsWeakReference) ||
-         aIID.equals(Ci.nsISupports))
-       return this;
-     throw Cr.NS_NOINTERFACE;
-    },
+    QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
+                                            "nsISupportsWeakReference"]),
 
     destroy() {
       if (this.webShell) {
         this.webShell.QueryInterface(Ci.nsIBaseWindow).destroy();
       }
       this.webShell = null;
       this.editor = null;
       this.resolve = null;
--- a/toolkit/content/browser-child.js
+++ b/toolkit/content/browser-child.js
@@ -227,26 +227,19 @@ var WebProgressListener = {
   onRefreshAttempted: function onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
     return true;
   },
 
   sendLoadCallResult() {
     sendAsyncMessage("Content:LoadURIResult");
   },
 
-  QueryInterface: function QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIWebProgressListener) ||
-        aIID.equals(Ci.nsIWebProgressListener2) ||
-        aIID.equals(Ci.nsISupportsWeakReference) ||
-        aIID.equals(Ci.nsISupports)) {
-        return this;
-    }
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
+                                          "nsIWebProgressListener2",
+                                          "nsISupportsWeakReference"]),
 };
 
 WebProgressListener.init();
 addEventListener("unload", () => {
   WebProgressListener.uninit();
 });
 
 var WebNavigation =  {
--- a/toolkit/content/contentAreaUtils.js
+++ b/toolkit/content/contentAreaUtils.js
@@ -243,25 +243,19 @@ function DownloadListener(win, transfer)
   // Now... we need to forward all calls to our transfer
   for (var i in transfer) {
     if (i != "QueryInterface")
       this[i] = makeClosure(i);
   }
 }
 
 DownloadListener.prototype = {
-  QueryInterface: function dl_qi(aIID) {
-    if (aIID.equals(Ci.nsIInterfaceRequestor) ||
-        aIID.equals(Ci.nsIWebProgressListener) ||
-        aIID.equals(Ci.nsIWebProgressListener2) ||
-        aIID.equals(Ci.nsISupports)) {
-      return this;
-    }
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIInterfaceRequestor",
+                                          "nsIWebProgressListener",
+                                          "nsIWebProgressListener2"]),
 
   getInterface: function dl_gi(aIID) {
     if (aIID.equals(Ci.nsIAuthPrompt) ||
         aIID.equals(Ci.nsIAuthPrompt2)) {
       var ww =
         Cc["@mozilla.org/embedcomp/window-watcher;1"]
           .getService(Ci.nsIPromptFactory);
       return ww.getPrompt(this.window, aIID);
@@ -1179,23 +1173,18 @@ function openURL(aURL) {
 
     var loadListener = {
       onStartRequest: function ll_start(aRequest, aContext) {
         appstartup.enterLastWindowClosingSurvivalArea();
       },
       onStopRequest: function ll_stop(aRequest, aContext, aStatusCode) {
         appstartup.exitLastWindowClosingSurvivalArea();
       },
-      QueryInterface: function ll_QI(iid) {
-        if (iid.equals(Ci.nsISupports) ||
-            iid.equals(Ci.nsIRequestObserver) ||
-            iid.equals(Ci.nsISupportsWeakReference))
-          return this;
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      }
+      QueryInterface: ChromeUtils.generateQI(["nsIRequestObserver",
+                                              "nsISupportsWeakReference"]),
     };
     loadgroup.groupObserver = loadListener;
 
     var uriListener = {
       onStartURIOpen(uri) { return false; },
       doContent(ctype, preferred, request, handler) { return false; },
       isPreferred(ctype, desired) { return false; },
       canHandleContent(ctype, preferred, desired) { return false; },
--- a/toolkit/modules/CertUtils.jsm
+++ b/toolkit/modules/CertUtils.jsm
@@ -199,23 +199,18 @@ BadCertHandler.prototype = {
   },
 
   // nsIInterfaceRequestor
   getInterface(iid) {
     return this.QueryInterface(iid);
   },
 
   // nsISupports
-  QueryInterface(iid) {
-    if (!iid.equals(Ci.nsIChannelEventSink) &&
-        !iid.equals(Ci.nsIInterfaceRequestor) &&
-        !iid.equals(Ci.nsISupports))
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    return this;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIChannelEventSink",
+                                          "nsIInterfaceRequestor"]),
 };
 
 var CertUtils = {
   BadCertHandler,
   checkCert,
   readCertPrefs,
   validateCert,
 };
--- a/toolkit/modules/FinderHighlighter.jsm
+++ b/toolkit/modules/FinderHighlighter.jsm
@@ -1694,23 +1694,17 @@ FinderHighlighter.prototype = {
    * to work out which editor was being destroyed. Therefore, we create new
    * listeners on the fly, and cache them in sync with the editors they
    * listen to.
    */
   _createStateListener() {
     return {
       findbar: this,
 
-      QueryInterface(iid) {
-        if (iid.equals(Ci.nsIDocumentStateListener) ||
-            iid.equals(Ci.nsISupports))
-          return this;
-
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      },
+      QueryInterface: ChromeUtils.generateQI(["nsIDocumentStateListener"]),
 
       NotifyDocumentWillBeDestroyed() {
         this.findbar._onEditorDestruction(this);
       },
 
       // Unimplemented
       notifyDocumentCreated() {},
       notifyDocumentStateChanged(aDirty) {}
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -365,29 +365,16 @@ ChannelEventSink.init();
 // nsIAuthPrompt2 implementation for onAuthRequired
 class AuthRequestor {
   constructor(channel, httpObserver) {
     this.notificationCallbacks = channel.notificationCallbacks;
     this.loadGroupCallbacks = channel.loadGroup && channel.loadGroup.notificationCallbacks;
     this.httpObserver = httpObserver;
   }
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIInterfaceRequestor) ||
-        iid.equals(Ci.nsIAuthPromptProvider) ||
-        iid.equals(Ci.nsIAuthPrompt2)) {
-      return this;
-    }
-    try {
-      return this.notificationCallbacks.QueryInterface(iid);
-    } catch (e) {}
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
-
   getInterface(iid) {
     if (iid.equals(Ci.nsIAuthPromptProvider) || iid.equals(Ci.nsIAuthPrompt2)) {
       return this;
     }
     try {
       return this.notificationCallbacks.getInterface(iid);
     } catch (e) {}
     throw Cr.NS_ERROR_NO_INTERFACE;
@@ -494,16 +481,22 @@ class AuthRequestor {
         }
         wrapper.authPromptForward = null;
         wrapper.authPromptCallback = null;
       },
     };
   }
 }
 
+AuthRequestor.prototype.QueryInterface = ChromeUtils.generateQI(
+  ["nsIInterfaceRequestor",
+   "nsIAuthPromptProvider",
+   "nsIAuthPrompt2"]);
+
+
 HttpObserverManager = {
   openingInitialized: false,
   modifyInitialized: false,
   examineInitialized: false,
   redirectInitialized: false,
   activityInitialized: false,
   needTracing: false,
   hasRedirects: false,
--- a/toolkit/mozapps/downloads/DownloadLastDir.jsm
+++ b/toolkit/mozapps/downloads/DownloadLastDir.jsm
@@ -35,23 +35,19 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 let nonPrivateLoadContext = Cc["@mozilla.org/loadcontext;1"].
                               createInstance(Ci.nsILoadContext);
 let privateLoadContext = Cc["@mozilla.org/privateloadcontext;1"].
                               createInstance(Ci.nsILoadContext);
 
 var observer = {
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIObserver) ||
-        aIID.equals(Ci.nsISupports) ||
-        aIID.equals(Ci.nsISupportsWeakReference))
-      return this;
-    throw Cr.NS_NOINTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIObserver",
+                                          "nsISupportsWeakReference"]),
+
   observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "last-pb-context-exited":
         gDownloadLastDirFile = null;
         break;
       case "browser:purge-session-history":
         gDownloadLastDirFile = null;
         if (Services.prefs.prefHasUserValue(LAST_DIR_PREF))
--- a/toolkit/mozapps/downloads/nsHelperAppDlg.js
+++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js
@@ -116,24 +116,18 @@ function nsUnknownContentTypeDialog() {
   this.mTitle    = "";
 }
 
 nsUnknownContentTypeDialog.prototype = {
   classID: Components.ID("{F68578EB-6EC2-4169-AE19-8C6243F0ABE1}"),
 
   nsIMIMEInfo: Ci.nsIMIMEInfo,
 
-  QueryInterface(iid) {
-    if (!iid.equals(Ci.nsIHelperAppLauncherDialog) &&
-        !iid.equals(Ci.nsITimerCallback) &&
-        !iid.equals(Ci.nsISupports)) {
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
-    return this;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIHelperAppLauncherDialog",
+                                          "nsITimerCallback"]),
 
   // ---------- nsIHelperAppLauncherDialog methods ----------
 
   // show: Open XUL dialog using window watcher.  Since the dialog is not
   //       modal, it needs to be a top level window and the way to open
   //       one of those is via that route).
   show(aLauncher, aContext, aReason) {
     this.mLauncher = aLauncher;
--- a/toolkit/mozapps/extensions/amWebAPI.js
+++ b/toolkit/mozapps/extensions/amWebAPI.js
@@ -254,20 +254,12 @@ class WebAPI extends APIObject {
   }
 
   eventListenerRemoved(type) {
     this.listenerCount--;
     if (this.listenerCount == 0) {
       this.broker.setAddonListener(null);
     }
   }
-
-  QueryInterface(iid) {
-    if (iid.equals(WebAPI.classID) || iid.equals(Ci.nsISupports)
-        || iid.equals(Ci.nsIDOMGlobalPropertyInitializer)) {
-      return this;
-    }
-    return Cr.NS_ERROR_NO_INTERFACE;
-  }
 }
-
+WebAPI.prototype.QueryInterface = ChromeUtils.generateQI(["nsIDOMGlobalPropertyInitializer"]);
 WebAPI.prototype.classID = Components.ID("{8866d8e3-4ea5-48b7-a891-13ba0ac15235}");
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebAPI]);
--- a/toolkit/mozapps/update/content/updates.js
+++ b/toolkit/mozapps/update/content/updates.js
@@ -542,22 +542,17 @@ var gCheckingPage = {
       LOG("gCheckingPage", "onError - proceeding to error page");
       gUpdates.setUpdate(update);
       gUpdates.wiz.goTo("errors");
     },
 
     /**
      * See nsISupports.idl
      */
-    QueryInterface(aIID) {
-      if (!aIID.equals(Ci.nsIUpdateCheckListener) &&
-          !aIID.equals(Ci.nsISupports))
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      return this;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIUpdateCheckListener"]),
   }
 };
 
 /**
  * The "No Updates Are Available" page
  */
 var gNoUpdatesPage = {
   /**