Bug 1402944: Part 10 - Minor runChannelListener cleanups/optimizaitons. r?mixedpuppy draft
authorKris Maglione <maglione.k@gmail.com>
Mon, 25 Sep 2017 14:01:12 -0700
changeset 670809 b91f2c7f93fcc7b8ff0ed123b3513d8cc181cc67
parent 670808 35f539a1d56a7009e170882ade7f00d2c9e2c1ae
child 670810 a5c69dc96f3330a3b78bf8161b83c88eff176608
push id81714
push usermaglione.k@gmail.com
push dateTue, 26 Sep 2017 21:30:45 +0000
reviewersmixedpuppy
bugs1402944
milestone58.0a1
Bug 1402944: Part 10 - Minor runChannelListener cleanups/optimizaitons. r?mixedpuppy Moving the event type lists to constants avoids array construction overhead for each event, and allows us to use the much faster Set.has rather than Array.includes. Using Object.create to add the base request info to the listener-specific info allows us to avoid object copy overhead. Switching to a .forEach() loop lets us avoid creating expensive live Map iterator objects, and also GC pressure caused by the huge number of iterator result objects and intermediate array objects created by for-of-entries(). It's otherwise just as fast as for-of in Ion. MozReview-Commit-ID: 53Fw1tJbuMY
toolkit/modules/addons/WebRequest.jsm
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -702,44 +702,45 @@ HttpObserverManager = {
         this.runChannelListener(channel, "onStart");
         break;
       case "stop":
         this.runChannelListener(channel, "onStop");
         break;
     }
   },
 
+  STATUS_TYPES: new Set(["headersReceived", "authRequired", "onRedirect", "onStart", "onStop"]),
+  FILTER_TYPES: new Set(["opening", "modify", "afterModify", "headersReceived", "authRequired", "onRedirect"]),
+
   runChannelListener(channel, kind, extraData = null) {
     let handlerResults = [];
     let requestHeaders;
     let responseHeaders;
 
     try {
       if (kind !== "onError" && channel.errorString) {
         return;
       }
 
-      let includeStatus = ["headersReceived", "authRequired", "onRedirect", "onStart", "onStop"].includes(kind);
-      let registerFilter = ["opening", "modify", "afterModify", "headersReceived", "authRequired", "onRedirect"].includes(kind);
-
+      let registerFilter = this.FILTER_TYPES.has(kind);
       let commonData = null;
       let requestBody;
-      for (let [callback, opts] of this.listeners[kind].entries()) {
+      this.listeners[kind].forEach((opts, callback) => {
         if (!channel.matches(opts.filter, opts.extension)) {
-          continue;
+          return;
         }
 
         if (!commonData) {
           commonData = this.getRequestData(channel, extraData);
-          if (includeStatus) {
+          if (this.STATUS_TYPES.has(kind)) {
             commonData.statusCode = channel.statusCode;
             commonData.statusLine = channel.statusLine;
           }
         }
-        let data = Object.assign({}, commonData);
+        let data = Object.create(commonData);
 
         if (registerFilter && opts.blocking && opts.extension) {
           channel.registerTraceableChannel(opts.extension, opts.tabParent);
         }
 
         if (opts.requestHeaders) {
           requestHeaders = requestHeaders || new RequestHeaderChanger(channel);
           data.requestHeaders = requestHeaders.toArray();
@@ -759,17 +760,17 @@ HttpObserverManager = {
           let result = callback(data);
 
           if (channel.canModify && result && typeof result === "object" && opts.blocking) {
             handlerResults.push({opts, result});
           }
         } catch (e) {
           Cu.reportError(e);
         }
-      }
+      });
     } catch (e) {
       Cu.reportError(e);
     }
 
     return this.applyChanges(kind, channel, handlerResults, requestHeaders, responseHeaders);
   },
 
   async applyChanges(kind, channel, handlerResults, requestHeaders, responseHeaders) {