merge m-c to fx-team
authorTim Taubert <ttaubert@mozilla.com>
Sat, 13 Oct 2012 23:20:19 +0200
changeset 110262 5c37e56564534853f8df69a99e3705a978c9cc5c
parent 110256 847807ab2646cc15d0f77c4876420a54fc61e758 (current diff)
parent 110261 4d3652c0a96f58e88aa18a6f412310de6d6e031f (diff)
child 110307 d750d39139d1bad9c744626c3b2852ac9a67463e
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone19.0a1
merge m-c to fx-team
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -164,41 +164,46 @@ function ResponsiveUI(aWindow, aTab)
   this.inspectorWasOpen = this.mainWindow.InspectorUI.isInspectorOpen;
 
   try {
     if (Services.prefs.getBoolPref("devtools.responsiveUI.rotate")) {
       this.rotate();
     }
   } catch(e) {}
 
-  switchToFloatingScrollbars(this.tab);
+  if (this._floatingScrollbars)
+    switchToFloatingScrollbars(this.tab);
+
   ResponsiveUIManager.events.emit("on", this.tab, this);
 }
 
 ResponsiveUI.prototype = {
   _transitionsEnabled: true,
+  _floatingScrollbars: false, // See bug 799471
   get transitionsEnabled() this._transitionsEnabled,
   set transitionsEnabled(aValue) {
     this._transitionsEnabled = aValue;
     if (aValue && !this._resizing && this.stack.hasAttribute("responsivemode")) {
       this.stack.removeAttribute("notransition");
     } else if (!aValue) {
       this.stack.setAttribute("notransition", "true");
     }
   },
 
   /**
    * Destroy the nodes. Remove listeners. Reset the style.
    */
   close: function RUI_unload() {
     if (this.closing)
       return;
-    switchToNativeScrollbars(this.tab);
     this.closing = true;
 
+    if (this._floatingScrollbars)
+      switchToNativeScrollbars(this.tab);
+
     this.unCheckMenus();
     // Reset style of the stack.
     let style = "max-width: none;" +
                 "min-width: 0;" +
                 "max-height: none;" +
                 "min-height: 0;";
     this.stack.setAttribute("style", style);
 
--- a/browser/devtools/responsivedesign/test/Makefile.in
+++ b/browser/devtools/responsivedesign/test/Makefile.in
@@ -40,28 +40,19 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_FILES = \
+		browser_responsiveui.js \
+		browser_responsiveuiaddcustompreset.js \
 		browser_responsiveruleview.js \
 		browser_responsive_cmd.js \
 		browser_responsivecomputedview.js \
 		head.js \
 		helpers.js \
 		$(NULL)
 
-# Disabled on Mac for frequent intermittent failures
-ifneq ($(OS_ARCH), Darwin)
-_BROWSER_FILES += \
-		browser_responsiveui.js \
-		browser_responsiveuiaddcustompreset.js \
-	$(NULL)
-else
-$(warning browser_responsiveui.js is disabled on OS X for intermittent failures. Bug 798772) \
-$(warning browser_responsiveuiaddcustompreset.js is disabled on OS X for intermittent failures. Bugs 798775, 798777)
-endif
-
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/devtools/responsivedesign/test/browser_responsiveui.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveui.js
@@ -27,17 +27,19 @@ function test() {
     is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
 
     // Menus are correctly updated?
     is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "true", "menus checked");
 
     instance = gBrowser.selectedTab.__responsiveUI;
     ok(instance, "instance of the module is attached to the tab.");
 
-    ensureScrollbarsAreFloating();
+    if (instance._floatingScrollbars) {
+      ensureScrollbarsAreFloating();
+    }
 
     instance.transitionsEnabled = false;
 
     testPresets();
   }
 
   function ensureScrollbarsAreFloating() {
     let body = gBrowser.contentDocument.body;
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -683,16 +683,28 @@ var Scratchpad = {
             file = aFile;
           } else {
             file = Components.classes["@mozilla.org/file/local;1"].
                    createInstance(Components.interfaces.nsILocalFile);
             let filePath = this.getRecentFiles()[aIndex];
             file.initWithPath(filePath);
           }
 
+          if (!file.exists()) {
+            this.notificationBox.appendNotification(
+              this.strings.GetStringFromName("fileNoLongerExists.notification"),
+              "file-no-longer-exists",
+              null,
+              this.notificationBox.PRIORITY_WARNING_HIGH,
+              null);
+
+            this.clearFiles(aIndex, 1);
+            return;
+          }
+
           this.setFilename(file.path);
           this.importFromFile(file, false);
           this.setRecentFile(file);
         }
       }.bind(this));
     }.bind(this);
 
     if (aIndex > -1) {
@@ -825,16 +837,33 @@ var Scratchpad = {
                               this.strings.
                               GetStringFromName("clearRecentMenuItems.label"));
       clearItems.setAttribute("command", "sp-cmd-clearRecentFiles");
       recentFilesPopup.appendChild(clearItems);
     }
   },
 
   /**
+   * Clear a range of files from the list.
+   *
+   * @param integer aIndex
+   *        Index of file in menu to remove.
+   * @param integer aLength
+   *        Number of files from the index 'aIndex' to remove.
+   */
+  clearFiles: function SP_clearFile(aIndex, aLength)
+  {
+    let filePaths = this.getRecentFiles();
+    let branch = Services.prefs.
+                 getBranch("devtools.scratchpad.");
+    filePaths.splice(aIndex, aLength);
+    branch.setCharPref("recentFilePaths", JSON.stringify(filePaths));
+  },
+
+  /**
    * Clear all recent files.
    */
   clearRecentFiles: function SP_clearRecentFiles()
   {
     Services.prefs.clearUserPref("devtools.scratchpad.recentFilePaths");
   },
 
   /**
@@ -854,21 +883,18 @@ var Scratchpad = {
           this.populateRecentFilesMenu();
         }
 
         menu.removeAttribute("hidden");
       }
 
       let filePaths = this.getRecentFiles();
       if (maxRecent < filePaths.length) {
-        let branch = Services.prefs.
-                     getBranch("devtools.scratchpad.");
         let diff = filePaths.length - maxRecent;
-        filePaths.splice(0, diff);
-        branch.setCharPref("recentFilePaths", JSON.stringify(filePaths));
+        this.clearFiles(0, diff);
       }
     }
   },
   /**
    * Save the textbox content to the currently open file.
    *
    * @param function aCallback
    *        Optional function you want to call when file is saved
--- a/browser/devtools/scratchpad/test/browser_scratchpad_bug_651942_recent_files.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug_651942_recent_files.js
@@ -96,45 +96,71 @@ function testOpenOldestRecent()
 // The "devtools.scratchpad.recentFilesMax"-preference was set to zero (0).
 // This should disable the "Open Recent"-menu by hiding it (this should not
 // remove any files from the list). Test to see if it's been hidden.
 function testHideMenu()
 {
   let menu = gScratchpadWindow.document.getElementById("sp-open_recent-menu");
   ok(menu.hasAttribute("hidden"), "The menu was hidden successfully.");
 
-  Services.prefs.setIntPref("devtools.scratchpad.recentFilesMax", 1);
+  Services.prefs.setIntPref("devtools.scratchpad.recentFilesMax", 2);
 }
 
 // We have set the recentFilesMax-pref to one (1), this enables the feature,
 // removes the two oldest files, rebuilds the menu and removes the
 // "hidden"-attribute from it. Test to see if this works.
 function testChangedMaxRecent()
 {
   let menu = gScratchpadWindow.document.getElementById("sp-open_recent-menu");
   ok(!menu.hasAttribute("hidden"), "The menu is visible. \\o/");
 
   lists.recentFiles04 = gScratchpad.getRecentFiles();
 
-  is(lists.recentFiles04.length, 1,
+  is(lists.recentFiles04.length, 2,
      "Two recent files were successfully removed from the 'recent files'-list");
 
   let doc = gScratchpadWindow.document;
   let popup = doc.getElementById("sp-menu-open_recentPopup");
 
   let menuitemLabel = popup.children[0].getAttribute("label");
   let correctMenuItem = false;
   if (menuitemLabel === lists.recentFiles03[2] &&
-      menuitemLabel === lists.recentFiles04[0]) {
+      menuitemLabel === lists.recentFiles04[1]) {
     correctMenuItem = true;
   }
 
   is(correctMenuItem, true,
      "Two recent files were successfully removed from the 'Open Recent'-menu");
 
+  // We now remove one file from the harddrive and use the recent-menuitem for
+  // it to make sure the user is notified that the file no longer exists.
+  // This is tested in testOpenDeletedFile().
+  gFile02.remove(false);
+  gFile02 = null;
+  gScratchpad.openFile(1);
+}
+
+// By now we should have two recent files stored in the list but one of the
+// files should be missing on the harddrive.
+function testOpenDeletedFile() {
+  let doc = gScratchpadWindow.document;
+  let popup = doc.getElementById("sp-menu-open_recentPopup");
+
+  is(gScratchpad.getRecentFiles().length, 1,
+     "The missing file was successfully removed from the list.");
+  // The number of recent files stored, plus the separator and the
+  // clearRecentMenuItems-item.
+  is(popup.children.length, 3,
+     "The missing file was successfully removed from the menu.");
+  ok(gScratchpad.notificationBox.currentNotification,
+     "The notification was successfully displayed.");
+  is(gScratchpad.notificationBox.currentNotification.label,
+     gScratchpad.strings.GetStringFromName("fileNoLongerExists.notification"),
+     "The notification label is correct.");
+
   gScratchpad.clearRecentFiles();
 }
 
 // We have cleared the last file. Test to see if the last file was removed,
 // the menu is empty and was disabled successfully.
 function testClearedAll()
 {
   let doc = gScratchpadWindow.document;
@@ -255,16 +281,20 @@ var PreferenceObserver = {
         testHideMenu();
         break;
       case 6:
         this.timesFired = 7;
         testChangedMaxRecent();
         break;
       case 7:
         this.timesFired = 8;
+        testOpenDeletedFile();
+        break;
+      case 8:
+        this.timesFired = 9;
         testClearedAll();
         break;
     }
   },
 
   uninit: function PO_uninit () {
     this.branch.removeObserver("", this);
   }
@@ -272,18 +302,17 @@ var PreferenceObserver = {
 
 function test()
 {
   waitForExplicitFinish();
 
   registerCleanupFunction(function () {
     gFile01.remove(false);
     gFile01 = null;
-    gFile02.remove(false);
-    gFile02 = null;
+    // gFile02 was removed earlier.
     gFile03.remove(false);
     gFile03 = null;
     gFile04.remove(false);
     gFile04 = null;
     lists.recentFiles01 = null;
     lists.recentFiles02 = null;
     lists.recentFiles03 = null;
     lists.recentFiles04 = null;
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js
@@ -49,32 +49,44 @@ function checkStyleEditorForSheetAndLine
       }
       return;
     }
 
     ok(true, "Correct Style Sheet is selected in the editor");
 
     // Editor is already loaded, check the current line of caret.
     if (aEditor.sourceEditor) {
+      ok(true, "Editor is already loaded, check the current line of caret");
       executeSoon(function() {
+        ok(true, "Execute soon occured");
+        ok(aEditor.sourceEditor != null, "sourceeditor not null");
+        ok(aEditor.sourceEditor.getCaretPosition() != null, "position not null");
+        ok(aEditor.sourceEditor.getCaretPosition().line != null, "line not null");
         is(aEditor.sourceEditor.getCaretPosition().line, aLine,
            "Correct line is selected");
         if (aCallback) {
           aCallback();
         }
       });
       return;
     }
 
+    ok(true, "Editor is not loaded, waiting for it.");
+    ok(aEditor, "aEditor is defined.");
     // Wait for source editor to be loaded.
     aEditor.addActionListener({
       onAttach: function onAttach() {
+        ok(true, "on attach happened");
         aEditor.removeActionListener(this);
-
+        ok(true, "this removed");
         executeSoon(function() {
+          ok(true, "execute soon");
+          ok(aEditor.sourceEditor != null, "sourceeditor not null");
+          ok(aEditor.sourceEditor.getCaretPosition() != null, "position not null");
+          ok(aEditor.sourceEditor.getCaretPosition().line != null, "line not null");
           is(aEditor.sourceEditor.getCaretPosition().line, aLine,
              "Correct line is selected");
           if (aCallback) {
             aCallback();
           }
         });
       }
     });
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -848,22 +848,22 @@ jsbJslintHappyDesc=Enforce jslint-strict
 # 'jsb <jslintHappy>' parameter, displayed when the user asks for help
 # on what it does.
 jsbJslintHappyManual=When set to true, jslint-stricter mode is enforced
 
 # LOCALIZATION NOTE (jsbBraceStyleDesc) A very short description of the
 # 'jsb <braceStyle>' parameter. This string is designed to be shown
 # in a menu alongside the command name, which is why it should be as short as
 # possible.
-jsbBraceStyleDesc=Select the coding style of braces
+jsbBraceStyleDesc=Collapse, expand, end-expand, expand-strict
 
 # LOCALIZATION NOTE (jsbBraceStyleManual) A fuller description of the
 # 'jsb <braceStyle>' parameter, displayed when the user asks for help
 # on what it does.
-jsbBraceStyleManual=<p class="nowrap">The coding style of braces. Select from one of the following:</p><ul><li>collapse<br/><pre>if (x == 1) {\n  ...\n} else {\n  ...\n}</pre></li><li>expand<br/><pre>if (x == 1)\n{\n  ...\n}\nelse\n{\n  ...\n}</pre></li><li>end-expand<br/><pre>if (x == 1) {\n  ...\n}\nelse {\n  ...\n}</pre></li><li>expand-strict<br/><pre>if (x == 1)\n{\n  return // This option can break scripts\n  {\n    a: 1\n  };\n} else {\n  ...\n}</pre></li></ul>
+jsbBraceStyleManual=The coding style of braces. Either collapse, expand, end-expand or expand-strict
 
 # LOCALIZATION NOTE (jsbNoSpaceBeforeConditionalDesc) A very short description
 # of the 'jsb <noSpaceBeforeConditional>' parameter. This string is designed to
 # be shown in a menu alongside the command name, which is why it should be as
 # short as possible.
 jsbNoSpaceBeforeConditionalDesc=No space before conditional statements
 
 # LOCALIZATION NOTE (jsbUnescapeStringsDesc) A very short description of the
--- a/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties
@@ -73,8 +73,12 @@ scratchpadIntro1=/*\n * This is a JavaSc
 
 # LOCALIZATION NOTE  (notification.browserContext): This is the message displayed
 # over the top of the editor when the user has switched to browser context.
 browserContext.notification=This scratchpad executes in the Browser context.
 
 # LOCALIZATION NOTE (help.openDocumentationPage): This returns a localized link with
 # documentation for Scratchpad on MDN.
 help.openDocumentationPage=https://developer.mozilla.org/en/Tools/Scratchpad
+
+# LOCALIZATION NOTE (fileExists.notification): This is the message displayed
+# over the top of the the editor when a file does not exist.
+fileNoLongerExists.notification=This file no longer exists.
--- a/toolkit/devtools/debugger/dbg-client.jsm
+++ b/toolkit/devtools/debugger/dbg-client.jsm
@@ -376,23 +376,26 @@ DebuggerClient.prototype = {
     });
   },
 
   /**
    * Release an object actor.
    *
    * @param string aActor
    *        The actor ID to send the request to.
+   * @param aOnResponse function
+   *        If specified, will be called with the response packet when
+   *        debugging server responds.
    */
-  release: function DC_release(aActor) {
+  release: function DC_release(aActor, aOnResponse) {
     let packet = {
       to: aActor,
       type: "release",
     };
-    this.request(packet);
+    this.request(packet, aOnResponse);
   },
 
   /**
    * Send a request to the debugging server.
    *
    * @param aRequest object
    *        A JSON packet to send to the debugging server.
    * @param aOnResponse function
@@ -782,16 +785,33 @@ ThreadClient.prototype = {
         aOnResponse(aResponse);
         return;
       }
       doSetBreakpoint(this.resume.bind(this));
     }.bind(this));
   },
 
   /**
+   * Release multiple thread-lifetime object actors. If any pause-lifetime
+   * actors are included in the request, a |notReleasable| error will return,
+   * but all the thread-lifetime ones will have been released.
+   *
+   * @param array aActors
+   *        An array with actor IDs to release.
+   */
+  releaseMany: function TC_releaseMany(aActors, aOnResponse) {
+    let packet = {
+      to: this._actor,
+      type: "releaseMany",
+      actors: aActors
+    };
+    this._client.request(packet, aOnResponse);
+  },
+
+  /**
    * Request the loaded scripts for the current thread.
    *
    * @param aOnResponse integer
    *        Called with the thread's response.
    */
   getScripts: function TC_getScripts(aOnResponse) {
     let packet = { to: this._actor, type: "scripts" };
     this._client.request(packet, aOnResponse);
--- a/toolkit/devtools/debugger/server/dbg-browser-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-browser-actors.js
@@ -275,18 +275,18 @@ BrowserTabActor.prototype = {
    */
   addToBreakpointPool: function BTA_addToBreakpointPool(aActor) {
     this.conn.addActor(aActor);
   },
 
   /**
    * Remove the specified breakpint from the default actor pool.
    *
-   * @param string aActor
-   *        The actor ID.
+   * @param BreakpointActor aActor
+   *        The actor object.
    */
   removeFromBreakpointPool: function BTA_removeFromBreakpointPool(aActor) {
     this.conn.removeActor(aActor);
   },
 
   // A constant prefix that will be used to form the actor ID by the server.
   actorPrefix: "tab",
 
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-script-actors.js
@@ -372,22 +372,29 @@ ThreadActor.prototype = {
   },
 
   onReleaseMany: function TA_onReleaseMany(aRequest) {
     if (!aRequest.actors) {
       return { error: "missingParameter",
                message: "no actors were specified" };
     }
 
+    let res;
     for each (let actorID in aRequest.actors) {
       let actor = this.threadLifetimePool.get(actorID);
-      this.threadLifetimePool.objectActors.delete(actor.obj);
-      this.threadLifetimePool.removeActor(actorID);
+      if (!actor) {
+        if (!res) {
+          res = { error: "notReleasable",
+                  message: "Only thread-lifetime actors can be released." };
+        }
+        continue;
+      }
+      actor.onRelease();
     }
-    return {};
+    return res ? res : {};
   },
 
   /**
    * Handle a protocol request to set a breakpoint.
    */
   onSetBreakpoint: function TA_onSetBreakpoint(aRequest) {
     if (this.state !== "paused") {
       return { error: "wrongState",
@@ -867,23 +874,30 @@ ThreadActor.prototype = {
     if (!this._pausePool) {
       throw "Object grip requested while not paused.";
     }
 
     return this.objectGrip(aValue, this._pausePool);
   },
 
   /**
-   * Create a grip for the given debuggee object with a thread lifetime.
+   * Extend the lifetime of the provided object actor to thread lifetime.
    *
-   * @param aValue Debugger.Object
-   *        The debuggee object value.
+   * @param aActor object
+   *        The object actor.
    */
-  threadObjectGrip: function TA_threadObjectGrip(aValue) {
-    return this.objectGrip(aValue, this.threadLifetimePool);
+  threadObjectGrip: function TA_threadObjectGrip(aActor) {
+    if (!this.threadLifetimePool.objectActors) {
+      this.threadLifetimePool.objectActors = new WeakMap();
+    }
+    // We want to reuse the existing actor ID, so we just remove it from the
+    // current pool's weak map and then let pool.addActor do the rest.
+    aActor.registeredPool.objectActors.delete(aActor.obj);
+    this.threadLifetimePool.addActor(aActor);
+    this.threadLifetimePool.objectActors.set(aActor.obj, aActor);
   },
 
   /**
    * Create a grip for the given string.
    *
    * @param aString String
    *        The string we are creating a grip for.
    * @param aPool ActorPool
@@ -1376,17 +1390,17 @@ update(ObjectActor.prototype, {
              "actor": this.actorID };
   },
 
   /**
    * Releases this actor from the pool.
    */
   release: function OA_release() {
     this.registeredPool.objectActors.delete(this.obj);
-    this.registeredPool.removeActor(this.actorID);
+    this.registeredPool.removeActor(this);
   },
 
   /**
    * Handle a protocol request to provide the names of the properties defined on
    * the object and not its prototype.
    *
    * @param aRequest object
    *        The protocol request object.
@@ -1538,29 +1552,30 @@ update(ObjectActor.prototype, {
   /**
    * Handle a protocol request to promote a pause-lifetime grip to a
    * thread-lifetime grip.
    *
    * @param aRequest object
    *        The protocol request object.
    */
   onThreadGrip: PauseScopedActor.withPaused(function OA_onThreadGrip(aRequest) {
-    return { threadGrip: this.threadActor.threadObjectGrip(this.obj) };
+    this.threadActor.threadObjectGrip(this);
+    return {};
   }),
 
   /**
    * Handle a protocol request to release a thread-lifetime grip.
    *
    * @param aRequest object
    *        The protocol request object.
    */
   onRelease: PauseScopedActor.withPaused(function OA_onRelease(aRequest) {
     if (this.registeredPool !== this.threadActor.threadLifetimePool) {
       return { error: "notReleasable",
-               message: "only thread-lifetime actors can be released." };
+               message: "Only thread-lifetime actors can be released." };
     }
 
     this.release();
     return {};
   }),
 });
 
 ObjectActor.prototype.requestTypes = {
@@ -1792,17 +1807,17 @@ BreakpointActor.prototype = {
    * @param aRequest object
    *        The protocol request object.
    */
   onDelete: function BA_onDelete(aRequest) {
     // Remove from the breakpoint store.
     let scriptBreakpoints = this.threadActor._breakpointStore[this.location.url];
     delete scriptBreakpoints[this.location.line];
     // Remove the actual breakpoint.
-    this.threadActor._hooks.removeFromBreakpointPool(this.actorID);
+    this.threadActor._hooks.removeFromBreakpointPool(this);
     for (let script of this.scripts) {
       script.clearBreakpoint(this);
     }
     this.scripts = null;
 
     return { from: this.actorID };
   }
 };
--- a/toolkit/devtools/debugger/server/dbg-server.js
+++ b/toolkit/devtools/debugger/server/dbg-server.js
@@ -386,19 +386,19 @@ ActorPool.prototype = {
    */
   isEmpty: function AP_isEmpty() {
     return Object.keys(this._actors).length == 0;
   },
 
   /**
    * Remove an actor from the actor pool.
    */
-  removeActor: function AP_remove(aActorID) {
-    delete this._actors[aActorID];
-    delete this._cleanups[aActorID];
+  removeActor: function AP_remove(aActor) {
+    delete this._actors[aActor.actorID];
+    delete this._cleanups[aActor.actorID];
   },
 
   /**
    * Run all cleanups previously registered with addCleanup.
    */
   cleanup: function AP_cleanup() {
     for each (let actor in this._cleanups) {
       actor.disconnect();
--- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js
+++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-01.js
@@ -23,33 +23,27 @@ function run_test()
   do_test_pending();
 }
 
 function test_thread_lifetime()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
     let pauseGrip = aPacket.frame.arguments[0];
 
+    // Create a thread-lifetime actor for this object.
     gClient.request({ to: pauseGrip.actor, type: "threadGrip" }, function(aResponse) {
-      let threadGrip = aResponse.threadGrip;
-
-      do_check_neq(pauseGrip.actor, threadGrip.actor);
-
-      // Create a thread-lifetime actor for this object.
-
+      // Successful promotion won't return an error.
+      do_check_eq(aResponse.error, undefined);
       gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
-        // Now that we've resumed, should get noSuchActor for the
-        // pause grip, but unrecognizePacketType for the thread grip.
-        gClient.request({ to: pauseGrip.actor, type: "bogusRequest" }, function(aResponse) {
-          do_check_eq(aResponse.error, "noSuchActor");
-          gClient.request({ to: threadGrip.actor, type: "bogusRequest"}, function(aResponse) {
-            do_check_eq(aResponse.error, "unrecognizedPacketType");
-            gThreadClient.resume(function() {
-              finishClient(gClient);
-            });
+        // Now that we've resumed, should get unrecognizePacketType for the
+        // promoted grip.
+        gClient.request({ to: pauseGrip.actor, type: "bogusRequest"}, function(aResponse) {
+          do_check_eq(aResponse.error, "unrecognizedPacketType");
+          gThreadClient.resume(function() {
+            finishClient(gClient);
           });
         });
       });
       gThreadClient.resume();
     });
   });
 
   gDebuggee.eval("(" + function() {
--- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js
+++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-02.js
@@ -23,23 +23,24 @@ function run_test()
   do_test_pending();
 }
 
 function test_thread_lifetime()
 {
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
     let pauseGrip = aPacket.frame.arguments[0];
 
+    // Create a thread-lifetime actor for this object.
     gClient.request({ to: pauseGrip.actor, type: "threadGrip" }, function(aResponse) {
-      let threadGrip = aResponse.threadGrip;
-      // Create a thread-lifetime actor for this object.
+      // Successful promotion won't return an error.
+      do_check_eq(aResponse.error, undefined);
       gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
         // Now that we've resumed, release the thread-lifetime grip.
-        gClient.request({ to: threadGrip.actor, type: "release" }, function(aResponse) {
-          gClient.request({ to: threadGrip.actor, type: "bogusRequest" }, function(aResponse) {
+        gClient.release(pauseGrip.actor, function(aResponse) {
+          gClient.request({ to: pauseGrip.actor, type: "bogusRequest" }, function(aResponse) {
             do_check_eq(aResponse.error, "noSuchActor");
             gThreadClient.resume(function(aResponse) {
               finishClient(gClient);
             });
           });
         });
       });
       gThreadClient.resume();
--- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js
+++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-03.js
@@ -26,17 +26,21 @@ function run_test()
 function test_thread_lifetime()
 {
   // Get three thread-lifetime grips.
   gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
     aPacket.frame.arguments[0];
     let grips = [];
 
     let handler = function(aResponse) {
-      grips.push(aResponse.threadGrip);
+      if (aResponse.error) {
+        do_check_eq(aResponse.error, '');
+        finishClient(gClient);
+      }
+      grips.push(aResponse.from);
       if (grips.length == 3) {
         test_release_many(grips);
       }
     };
     for (let i = 0; i < 3; i++) {
       gClient.request({ to: aPacket.frame.arguments[i].actor, type: "threadGrip" },
                       handler);
     }
@@ -50,29 +54,29 @@ function test_thread_lifetime()
     ")"
   } + ")()");
 }
 
 function test_release_many(grips)
 {
   // Release the first two grips, leave the third alive.
 
-  let release = [grips[0].actor, grips[1].actor];
+  let release = [grips[0], grips[1]];
 
-  gClient.request({ to: gThreadClient.actor, type: "releaseMany", "actors": release }, function(aResponse) {
+  gThreadClient.releaseMany(release, function(aResponse) {
     // First two actors should return a noSuchActor error, because
     // they're gone now.
-    gClient.request({ to: grips[0].actor, type: "bogusRequest" }, function(aResponse) {
+    gClient.request({ to: grips[0], type: "bogusRequest" }, function(aResponse) {
       do_check_eq(aResponse.error, "noSuchActor");
-      gClient.request({ to: grips[1].actor, type: "bogusRequest" }, function(aResponse) {
+      gClient.request({ to: grips[1], type: "bogusRequest" }, function(aResponse) {
         do_check_eq(aResponse.error, "noSuchActor");
 
         // Last actor should return unrecognizedPacketType, because it's still
         // alive.
-        gClient.request({ to: grips[2].actor, type: "bogusRequest" }, function(aResponse) {
+        gClient.request({ to: grips[2], type: "bogusRequest" }, function(aResponse) {
           do_check_eq(aResponse.error, "unrecognizedPacketType");
           gThreadClient.resume(function() {
             finishClient(gClient);
           });
         });
       });
     });
   });
--- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-04.js
+++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-04.js
@@ -25,22 +25,23 @@ function run_test()
 }
 
 function test_thread_lifetime()
 {
   gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
     let pauseGrip = aPacket.frame.arguments[0];
 
     gClient.request({ to: pauseGrip.actor, type: "threadGrip" }, function (aResponse) {
-      let threadGrip1 = aResponse.threadGrip;
+      // Successful promotion won't return an error.
+      do_check_eq(aResponse.error, undefined);
 
-      do_check_neq(pauseGrip.actor, threadGrip1.actor);
+      let threadGrip1 = aResponse.from;
 
       gClient.request({ to: pauseGrip.actor, type: "threadGrip" }, function (aResponse) {
-        do_check_eq(threadGrip1.actor, aResponse.threadGrip.actor);
+        do_check_eq(threadGrip1, aResponse.from);
         gThreadClient.resume(function() {
           finishClient(gClient);
         });
       });
     });
   });
 
   gDebuggee.eval("(" + function() {
--- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js
+++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js
@@ -1,19 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
- * Make sure that an actor will not be reused after a release or
- * releaseMany.
+ * Make sure that releasing a pause-lifetime actorin a releaseMany returns an
+ * error, but releases all the thread-lifetime actors.
  */
 
 var gDebuggee;
 var gClient;
 var gThreadClient;
+var gPauseGrip;
 
 function run_test()
 {
   initTestDebuggerServer();
   gDebuggee = addTestGlobal("test-grips");
   gClient = new DebuggerClient(DebuggerServer.connectPipe());
   gClient.connect(function() {
     attachTestGlobalClientAndResume(gClient, "test-grips", function(aResponse, aThreadClient) {
@@ -22,33 +23,38 @@ function run_test()
     });
   });
   do_test_pending();
 }
 
 function arg_grips(aFrameArgs, aOnResponse) {
   let grips = [];
   let handler = function (aResponse) {
-    grips.push(aResponse.threadGrip);
+    if (aResponse.error) {
+      grips.push(aResponse.error);
+    } else {
+      grips.push(aResponse.from);
+    }
     if (grips.length == aFrameArgs.length) {
       aOnResponse(grips);
     }
   };
   for (let i = 0; i < aFrameArgs.length; i++) {
     gClient.request({ to: aFrameArgs[i].actor, type: "threadGrip" },
                     handler);
   }
 }
 
 function test_thread_lifetime()
 {
-  // Get three thread-lifetime grips.
+  // Get two thread-lifetime grips.
   gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
 
-    let frameArgs = aPacket.frame.arguments;
+    let frameArgs = [ aPacket.frame.arguments[0], aPacket.frame.arguments[1] ];
+    gPauseGrip = aPacket.frame.arguments[2];
     arg_grips(frameArgs, function (aGrips) {
       release_grips(frameArgs, aGrips);
     });
   });
 
   gDebuggee.eval("(" + function() {
     function stopMe(arg1, arg2, arg3) {
       debugger;
@@ -56,25 +62,23 @@ function test_thread_lifetime()
     stopMe({obj: 1}, {obj: 2}, {obj: 3});
     ")"
   } + ")()");
 }
 
 
 function release_grips(aFrameArgs, aThreadGrips)
 {
-  // Release the first grip with release, and the second two with releaseMany...
-
-  gClient.request({ to: aThreadGrips[0].actor, type: "release" }, function (aResponse) {
-    let release = [aThreadGrips[1].actor, aThreadGrips[2].actor];
-    gClient.request({ to: gThreadClient.actor, type: "releaseMany", "actors": release }, function (aResponse) {
-      // Now ask for thread grips again, they should be different.
-      arg_grips(aFrameArgs, function (aNewGrips) {
-        for (let i = 0; i < aNewGrips.length; i++) {
-          do_check_neq(aThreadGrips[i].actor, aNewGrips[i].actor);
-        }
-        gThreadClient.resume(function () {
-          finishClient(gClient);
-        });
+  // Release all actors with releaseMany...
+  let release = [aThreadGrips[0], aThreadGrips[1], gPauseGrip.actor];
+  gThreadClient.releaseMany(release, function (aResponse) {
+    do_check_eq(aResponse.error, "notReleasable");
+    // Now ask for thread grips again, they should not exist.
+    arg_grips(aFrameArgs, function (aNewGrips) {
+      for (let i = 0; i < aNewGrips.length; i++) {
+        do_check_eq(aNewGrips[i], "noSuchActor");
+      }
+      gThreadClient.resume(function () {
+        finishClient(gClient);
       });
     });
   });
 }