Bug 877773 - If Browser console is staying opened, Browser UI freezes for a while when open youtube page; r=robcee
authorMihai Sucan <mihai.sucan@gmail.com>
Tue, 04 Jun 2013 18:47:39 +0300
changeset 134272 72b10430789049c46fe5653cf0f4e26ac65c6695
parent 134271 76bea01d8db1d30c660e42229447d0b89af60ed5
child 134273 c41a3e24a574377f2d443a7783c4a2011c413f1b
push id24790
push userryanvm@gmail.com
push dateFri, 07 Jun 2013 15:05:33 +0000
treeherdermozilla-central@c41a3e24a574 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrobcee
bugs877773
milestone24.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 877773 - If Browser console is staying opened, Browser UI freezes for a while when open youtube page; r=robcee
browser/devtools/webconsole/webconsole.js
toolkit/devtools/server/actors/webconsole.js
toolkit/devtools/webconsole/WebConsoleUtils.jsm
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -1187,24 +1187,44 @@ WebConsoleFrame.prototype = {
   {
     // Warnings and legacy strict errors become warnings; other types become
     // errors.
     let severity = SEVERITY_ERROR;
     if (aScriptError.warning || aScriptError.strict) {
       severity = SEVERITY_WARNING;
     }
 
+    let objectActors = new Set();
+
+    // Gather the actor IDs.
+    for (let prop of ["errorMessage", "lineText"]) {
+      let grip = aScriptError[prop];
+      if (WebConsoleUtils.isActorGrip(grip)) {
+        objectActors.add(grip.actor);
+      }
+    }
+
+    let errorMessage = aScriptError.errorMessage;
+    if (errorMessage.type && errorMessage.type == "longString") {
+      errorMessage = errorMessage.initial;
+    }
+
     let node = this.createMessageNode(aCategory, severity,
-                                      aScriptError.errorMessage,
+                                      errorMessage,
                                       aScriptError.sourceName,
                                       aScriptError.lineNumber, null, null,
                                       aScriptError.timeStamp);
     if (aScriptError.private) {
       node.setAttribute("private", true);
     }
+
+    if (objectActors.size > 0) {
+      node._objectActors = objectActors;
+    }
+
     return node;
   },
 
   /**
    * Handle PageError objects received from the server. This method outputs the
    * given error.
    *
    * @param nsIScriptError aPageError
@@ -1220,20 +1240,42 @@ WebConsoleFrame.prototype = {
    * Handle log messages received from the server. This method outputs the given
    * message.
    *
    * @param object aPacket
    *        The message packet received from the server.
    */
   handleLogMessage: function WCF_handleLogMessage(aPacket)
   {
-    this.outputMessage(CATEGORY_JS, () => {
-      return this.createMessageNode(CATEGORY_JS, SEVERITY_LOG, aPacket.message,
-                                    null, null, null, null, aPacket.timeStamp);
-    });
+    if (aPacket.message) {
+      this.outputMessage(CATEGORY_JS, this._reportLogMessage, [aPacket]);
+    }
+  },
+
+  /**
+   * Display log messages received from the server.
+   *
+   * @private
+   * @param object aPacket
+   *        The message packet received from the server.
+   * @return nsIDOMElement
+   *         The message element to render for the given log message.
+   */
+  _reportLogMessage: function WCF__reportLogMessage(aPacket)
+  {
+    let msg = aPacket.message;
+    if (msg.type && msg.type == "longString") {
+      msg = msg.initial;
+    }
+    let node = this.createMessageNode(CATEGORY_JS, SEVERITY_LOG, msg, null,
+                                      null, null, null, aPacket.timeStamp);
+    if (WebConsoleUtils.isActorGrip(aPacket.message)) {
+      node._objectActors = new Set([aPacket.message.actor]);
+    }
+    return node;
   },
 
   /**
    * Log network event.
    *
    * @param object aActorId
    *        The network event actor ID to log.
    * @return nsIDOMElement|null
@@ -1987,16 +2029,32 @@ WebConsoleFrame.prototype = {
     else if (category == CATEGORY_WEBDEV &&
              methodOrNode == this.logConsoleAPIMessage) {
       args[0].arguments.forEach((aValue) => {
         if (WebConsoleUtils.isActorGrip(aValue)) {
           this._releaseObject(aValue.actor);
         }
       });
     }
+    else if (category == CATEGORY_JS &&
+             methodOrNode == this.reportPageError) {
+      let pageError = args[1];
+      for (let prop of ["errorMessage", "lineText"]) {
+        let grip = pageError[prop];
+        if (WebConsoleUtils.isActorGrip(grip)) {
+          this._releaseObject(grip.actor);
+        }
+      }
+    }
+    else if (category == CATEGORY_JS &&
+             methodOrNode == this._reportLogMessage) {
+      if (WebConsoleUtils.isActorGrip(args[0].message)) {
+        this._releaseObject(args[0].message.actor);
+      }
+    }
   },
 
   /**
    * Ensures that the number of message nodes of type aCategory don't exceed that
    * category's line limit by removing old messages as needed.
    *
    * @param integer aCategory
    *        The category of message nodes to prune if needed.
--- a/toolkit/devtools/server/actors/webconsole.js
+++ b/toolkit/devtools/server/actors/webconsole.js
@@ -337,16 +337,34 @@ WebConsoleActor.prototype =
   longStringGrip: function WCA_longStringGrip(aString, aPool)
   {
     let actor = new LongStringActor(aString, this);
     aPool.addActor(actor);
     return actor.grip();
   },
 
   /**
+   * Create a long string grip if needed for the given string.
+   *
+   * @private
+   * @param string aString
+   *        The string you want to create a long string grip for.
+   * @return string|object
+   *         A string is returned if |aString| is not a long string.
+   *         A LongStringActor grip is returned if |aString| is a long string.
+   */
+  _createStringGrip: function NEA__createStringGrip(aString)
+  {
+    if (aString && this._stringIsLong(aString)) {
+      return this.longStringGrip(aString, this._actorPool);
+    }
+    return aString;
+  },
+
+  /**
    * Get an object actor by its ID.
    *
    * @param string aActorID
    * @return object
    */
   getActorByID: function WCA_getActorByID(aActorID)
   {
     return this._actorPool.get(aActorID);
@@ -908,17 +926,17 @@ WebConsoleActor.prototype =
         type: "pageError",
         pageError: this.preparePageErrorForRemote(aMessage),
       };
     }
     else {
       packet = {
         from: this.actorID,
         type: "logMessage",
-        message: aMessage.message,
+        message: this._createStringGrip(aMessage.message),
         timeStamp: aMessage.timeStamp,
       };
     }
     this.conn.send(packet);
   },
 
   /**
    * Prepare an nsIScriptError to be sent to the client.
@@ -926,20 +944,19 @@ WebConsoleActor.prototype =
    * @param nsIScriptError aPageError
    *        The page error we need to send to the client.
    * @return object
    *         The object you can send to the remote client.
    */
   preparePageErrorForRemote: function WCA_preparePageErrorForRemote(aPageError)
   {
     return {
-      message: aPageError.message,
-      errorMessage: aPageError.errorMessage,
+      errorMessage: this._createStringGrip(aPageError.errorMessage),
       sourceName: aPageError.sourceName,
-      lineText: aPageError.sourceLine,
+      lineText: this._createStringGrip(aPageError.sourceLine),
       lineNumber: aPageError.lineNumber,
       columnNumber: aPageError.columnNumber,
       category: aPageError.category,
       timeStamp: aPageError.timeStamp,
       warning: !!(aPageError.flags & aPageError.warningFlag),
       error: !!(aPageError.flags & aPageError.errorFlag),
       exception: !!(aPageError.flags & aPageError.exceptionFlag),
       strict: !!(aPageError.flags & aPageError.strictFlag),
@@ -1134,16 +1151,18 @@ function NetworkEventActor(aNetworkEvent
 
   this._response = {
     headers: [],
     cookies: [],
     content: {},
   };
 
   this._timings = {};
+
+  // Keep track of LongStringActors owned by this NetworkEventActor.
   this._longStringActors = new Set();
 
   this._discardRequestBody = aNetworkEvent.discardRequestBody;
   this._discardResponseBody = aNetworkEvent.discardResponseBody;
   this._private = aNetworkEvent.private;
 }
 
 NetworkEventActor.prototype =
@@ -1348,17 +1367,17 @@ NetworkEventActor.prototype =
    * Add network request POST data.
    *
    * @param object aPostData
    *        The request POST data.
    */
   addRequestPostData: function NEA_addRequestPostData(aPostData)
   {
     this._request.postData = aPostData;
-    aPostData.text = this._createStringGrip(aPostData.text);
+    aPostData.text = this.parent._createStringGrip(aPostData.text);
     if (typeof aPostData.text == "object") {
       this._longStringActors.add(aPostData.text);
     }
 
     let packet = {
       from: this.actorID,
       type: "networkEventUpdate",
       updateType: "requestPostData",
@@ -1443,17 +1462,17 @@ NetworkEventActor.prototype =
    *        The response content.
    * @param boolean aDiscardedResponseBody
    *        Tells if the response content was recorded or not.
    */
   addResponseContent:
   function NEA_addResponseContent(aContent, aDiscardedResponseBody)
   {
     this._response.content = aContent;
-    aContent.text = this._createStringGrip(aContent.text);
+    aContent.text = this.parent._createStringGrip(aContent.text);
     if (typeof aContent.text == "object") {
       this._longStringActors.add(aContent.text);
     }
 
     let packet = {
       from: this.actorID,
       type: "networkEventUpdate",
       updateType: "responseContent",
@@ -1493,40 +1512,22 @@ NetworkEventActor.prototype =
    * LongStringActor for the header values, when needed.
    *
    * @private
    * @param array aHeaders
    */
   _prepareHeaders: function NEA__prepareHeaders(aHeaders)
   {
     for (let header of aHeaders) {
-      header.value = this._createStringGrip(header.value);
+      header.value = this.parent._createStringGrip(header.value);
       if (typeof header.value == "object") {
         this._longStringActors.add(header.value);
       }
     }
   },
-
-  /**
-   * Create a long string grip if needed for the given string.
-   *
-   * @private
-   * @param string aString
-   *        The string you want to create a long string grip for.
-   * @return string|object
-   *         A string is returned if |aString| is not a long string.
-   *         A LongStringActor grip is returned if |aString| is a long string.
-   */
-  _createStringGrip: function NEA__createStringGrip(aString)
-  {
-    if (this.parent._stringIsLong(aString)) {
-      return this.parent.longStringGrip(aString, this.parent._actorPool);
-    }
-    return aString;
-  },
 };
 
 NetworkEventActor.prototype.requestTypes =
 {
   "release": NetworkEventActor.prototype.onRelease,
   "getRequestHeaders": NetworkEventActor.prototype.onGetRequestHeaders,
   "getRequestCookies": NetworkEventActor.prototype.onGetRequestCookies,
   "getRequestPostData": NetworkEventActor.prototype.onGetRequestPostData,
--- a/toolkit/devtools/webconsole/WebConsoleUtils.jsm
+++ b/toolkit/devtools/webconsole/WebConsoleUtils.jsm
@@ -940,19 +940,17 @@ ConsoleServiceListener.prototype =
       }
 
       let errorWindow = Services.wm.getOuterWindowWithId(aMessage.outerWindowID);
       if (!errorWindow || errorWindow.top != this.window) {
         return;
       }
     }
 
-    if (aMessage.message) {
-      this.listener.onConsoleServiceMessage(aMessage);
-    }
+    this.listener.onConsoleServiceMessage(aMessage);
   },
 
   /**
    * Check if the given message category is allowed to be tracked or not.
    * We ignore chrome-originating errors as we only care about content.
    *
    * @param string aCategory
    *        The message category you want to check.