Backed out 3 changesets (bug 1227978) for XPCShell and dt3 bustage on a CLOSED TREE. r=backout
authorSebastian Hengst <archaeopteryx@coole-files.de>
Fri, 08 Jan 2016 19:03:25 +0100
changeset 320162 8badb4d61bc8d55863e5658ffba6fccdcf8bb935
parent 320161 105bbb3e0c5a5d59ea2b167fca4b44b8b8fb33a8
child 320163 d8f3e275f36eac27a835c0c13a83e1a866a39503
push id9143
push userahunt@mozilla.com
push dateFri, 08 Jan 2016 21:30:53 +0000
reviewersbackout
bugs1227978
milestone46.0a1
backs outd8a429b575e3359ceaa13d2ae2b7bcfc4e3d730b
f99079d057cc45414b8e894c3703ee0221fe3f99
8b4ced39ad5858ae05a65998676e4c1ffea859da
Backed out 3 changesets (bug 1227978) for XPCShell and dt3 bustage on a CLOSED TREE. r=backout Backed out changeset d8a429b575e3 (bug 1227978) Backed out changeset f99079d057cc (bug 1227978) Backed out changeset 8b4ced39ad58 (bug 1227978)
devtools/client/debugger/content/actions/breakpoints.js
devtools/client/debugger/content/actions/event-listeners.js
devtools/client/debugger/content/actions/sources.js
devtools/client/debugger/content/utils.js
devtools/client/debugger/debugger-view.js
devtools/client/debugger/test/mochitest/browser_dbg_interrupts.js
devtools/client/debugger/test/mochitest/browser_dbg_listtabs-03.js
devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-06.js
devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-on-paused.js
devtools/client/debugger/test/mochitest/browser_dbg_scripts-switching-03.js
devtools/client/debugger/test/mochitest/head.js
devtools/client/framework/connect/connect.js
devtools/client/inspector/markup/test/head.js
devtools/client/performance/legacy/front.js
devtools/client/performance/test/browser_perf-legacy-front-05.js
devtools/server/tests/browser/browser_stylesheets_getTextEmpty.js
devtools/server/tests/browser/browser_stylesheets_nested-iframes.js
devtools/server/tests/mochitest/director-helpers.js
devtools/server/tests/unit/head_dbg.js
devtools/shared/client/main.js
--- a/devtools/client/debugger/content/actions/breakpoints.js
+++ b/devtools/client/debugger/content/actions/breakpoints.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const constants = require('../constants');
 const promise = require('promise');
-const { asPaused } = require('../utils');
+const { asPaused, rdpInvoke } = require('../utils');
 const { PROMISE } = require('devtools/client/shared/redux/middleware/promise');
 const {
   getSource, getBreakpoint, getBreakpoints, makeLocationId
 } = require('../queries');
 
 // Because breakpoints are just simple data structures, we still need
 // a way to lookup the actual client instance to talk to the server.
 // We keep an internal database of clients based off of actor ID.
@@ -50,17 +50,17 @@ function addBreakpoint(location, conditi
     return dispatch({
       type: constants.ADD_BREAKPOINT,
       breakpoint: bp,
       condition: condition,
       [PROMISE]: Task.spawn(function*() {
         const sourceClient = gThreadClient.source(
           getSource(getState(), bp.location.actor)
         );
-        const [response, bpClient] = yield sourceClient.setBreakpoint({
+        const [response, bpClient] = yield rdpInvoke(sourceClient, sourceClient.setBreakpoint, {
           line: bp.location.line,
           column: bp.location.column,
           condition: bp.condition
         });
         const { isPending, actualLocation } = response;
 
         // Save the client instance
         setBreakpointClient(bpClient.actor, bpClient);
@@ -100,17 +100,17 @@ function _removeOrDisableBreakpoint(loca
     }
 
     const bpClient = getBreakpointClient(bp.actor);
 
     return dispatch({
       type: constants.REMOVE_BREAKPOINT,
       breakpoint: bp,
       disabled: isDisabled,
-      [PROMISE]: bpClient.remove()
+      [PROMISE]: rdpInvoke(bpClient, bpClient.remove)
     });
   }
 }
 
 function removeAllBreakpoints() {
   return (dispatch, getState) => {
     const breakpoints = getBreakpoints(getState());
     const activeBreakpoints = breakpoints.filter(bp => !bp.disabled);
--- a/devtools/client/debugger/content/actions/event-listeners.js
+++ b/devtools/client/debugger/content/actions/event-listeners.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const constants = require("../constants");
-const { asPaused } = require("../utils");
+const { rdpInvoke, asPaused } = require("../utils");
 const { reportException } = require("devtools/shared/DevToolsUtils");
 
 const FETCH_EVENT_LISTENERS_DELAY = 200; // ms
 
 function fetchEventListeners() {
   return (dispatch, getState) => {
     // Make sure we"re not sending a batch of closely repeated requests.
     // This can easily happen whenever new sources are fetched.
@@ -45,17 +45,17 @@ function fetchEventListeners() {
           listeners: listeners
         });
       });
     });
   };
 }
 
 const _getListeners = Task.async(function*() {
-  const response = yield gThreadClient.eventListeners();
+  const response = yield rdpInvoke(gThreadClient, gThreadClient.eventListeners);
 
   // Make sure all the listeners are sorted by the event type, since
   // they"re not guaranteed to be clustered together.
   response.listeners.sort((a, b) => a.type > b.type ? 1 : -1);
 
   // Add all the listeners in the debugger view event linsteners container.
   let fetchedDefinitions = new Map();
   let listeners = [];
@@ -81,17 +81,17 @@ const _getListeners = Task.async(functio
   return listeners;
 });
 
 const _getDefinitionSite = Task.async(function*(aFunction) {
   const grip = gThreadClient.pauseGrip(aFunction);
   let response;
 
   try {
-    response = yield grip.getDefinitionSite();
+    response = yield rdpInvoke(grip, grip.getDefinitionSite);
   }
   catch(e) {
     // Don't make this error fatal, because it would break the entire events pane.
     reportException("_getDefinitionSite", e);
     return null;
   }
 
   return response.source.url;
--- a/devtools/client/debugger/content/actions/sources.js
+++ b/devtools/client/debugger/content/actions/sources.js
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const constants = require('../constants');
 const promise = require('promise');
+const { rdpInvoke } = require('../utils');
 const { dumpn } = require("devtools/shared/DevToolsUtils");
 const { PROMISE, HISTOGRAM_ID } = require('devtools/client/shared/redux/middleware/promise');
 const { getSource, getSourceText } = require('../queries');
 
 const NEW_SOURCE_IGNORED_URLS = ["debugger eval code", "XStringBundle"];
 const FETCH_SOURCE_RESPONSE_DELAY = 200; // ms
 
 function getSourceClient(source) {
@@ -56,17 +57,17 @@ function selectSource(source, opts) {
     });
   };
 }
 
 function loadSources() {
   return {
     type: constants.LOAD_SOURCES,
     [PROMISE]: Task.spawn(function*() {
-      const response = yield gThreadClient.getSources();
+      const response = yield rdpInvoke(gThreadClient, gThreadClient.getSources);
 
       // Top-level breakpoints may pause the entire loading process
       // because scripts are executed as they are loaded, so the
       // engine may pause in the middle of loading all the sources.
       // This is relatively harmless, as individual `newSource`
       // notifications are fired for each script and they will be
       // added to the UI through that.
       if (!response.sources) {
@@ -98,17 +99,18 @@ function loadSources() {
  */
 function blackbox(source, shouldBlackBox) {
   const client = getSourceClient(source);
 
   return {
     type: constants.BLACKBOX,
     source: source,
     [PROMISE]: Task.spawn(function*() {
-      yield shouldBlackBox ? client.blackBox() : client.unblackBox();
+      yield rdpInvoke(client,
+                      shouldBlackBox ? client.blackBox : client.unblackBox);
       return {
         isBlackBoxed: shouldBlackBox
       }
     })
   };
 }
 
 /**
@@ -136,20 +138,23 @@ function togglePrettyPrint(source) {
         // Only attempt to pretty print JavaScript sources.
         const sourceText = getSourceText(getState(), source.actor);
         const contentType = sourceText ? sourceText.contentType : null;
         if (!SourceUtils.isJavaScript(source.url, contentType)) {
           throw new Error("Can't prettify non-javascript files.");
         }
 
         if (wantPretty) {
-          response = yield sourceClient.prettyPrint(Prefs.editorTabSize);
+          response = yield rdpInvoke(sourceClient,
+                                     sourceClient.prettyPrint,
+                                     Prefs.editorTabSize);
         }
         else {
-          response = yield sourceClient.disablePrettyPrint();
+          response = yield rdpInvoke(sourceClient,
+                                     sourceClient.disablePrettyPrint);
         }
 
         // Remove the cached source AST from the Parser, to avoid getting
         // wrong locations when searching for functions.
         DebuggerController.Parser.clearSource(source.url);
 
         return {
           isPrettyPrinted: wantPretty,
@@ -176,17 +181,17 @@ function loadSourceText(source) {
       type: constants.LOAD_SOURCE_TEXT,
       source: source,
       [PROMISE]: Task.spawn(function*() {
         let transportType = gClient.localTransport ? "_LOCAL" : "_REMOTE";
         let histogramId = "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE" + transportType + "_MS";
         let histogram = Services.telemetry.getHistogramById(histogramId);
         let startTime = Date.now();
 
-        const response = yield sourceClient.source();
+        const response = yield rdpInvoke(sourceClient, sourceClient.source);
 
         histogram.add(Date.now() - startTime);
 
         // Automatically pretty print if enabled and the test is
         // detected to be "minified"
         if (Prefs.autoPrettyPrint &&
             !source.isPrettyPrinted &&
             SourceUtils.isMinified(source.actor, response.source)) {
--- a/devtools/client/debugger/content/utils.js
+++ b/devtools/client/debugger/content/utils.js
@@ -1,32 +1,50 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
+const { promiseInvoke } = require("devtools/shared/async-utils");
 const { reportException } = require("devtools/shared/DevToolsUtils");
 
+// RDP utils
+
+function rdpInvoke(client, method, ...args) {
+  return (promiseInvoke(client, method, ...args)
+    .then((packet) => {
+      if (packet.error) {
+        let { error, message } = packet;
+        const err = new Error(error + ": " + message);
+        err.rdpError = error;
+        err.rdpMessage = message;
+        throw err;
+      }
+
+      return packet;
+    }));
+}
+
 function asPaused(client, func) {
   if (client.state != "paused") {
     return Task.spawn(function*() {
-      yield client.interrupt();
+      yield rdpInvoke(client, client.interrupt);
       let result;
 
       try {
         result = yield func();
       }
       catch(e) {
         // Try to put the debugger back in a working state by resuming
         // it
-        yield client.resume();
+        yield rdpInvoke(client, client.resume);
         throw e;
       }
 
-      yield client.resume();
+      yield rdpInvoke(client, client.resume);
       return result;
     });
   } else {
     return func();
   }
 }
 
 function handleError(err) {
@@ -70,16 +88,17 @@ function updateIn(destObj, path, fn) {
 function deleteIn(destObj, path) {
   const objPath = path.slice(0, -1);
   const propName = path[path.length - 1];
   const obj = _getIn(destObj, objPath);
   return setIn(destObj, objPath, obj.without(propName));
 }
 
 module.exports = {
+  rdpInvoke,
   asPaused,
   handleError,
   onReducerEvents,
   mergeIn,
   setIn,
   updateIn,
   deleteIn
 };
--- a/devtools/client/debugger/debugger-view.js
+++ b/devtools/client/debugger/debugger-view.js
@@ -477,17 +477,18 @@ var DebuggerView = {
     if (textInfo.loading) {
       // TODO: bug 1228866, we need to update `_editorSource` here but
       // still make the editor be updated when the full text comes
       // through somehow.
       this._setEditorText(L10N.getStr("loadingText"));
       return;
     }
     else if (textInfo.error) {
-      let msg = L10N.getFormatStr("errorLoadingText2", textInfo.error);
+      let url = textInfo.error;
+      let msg = L10N.getFormatStr("errorLoadingText2", url);
       this._setEditorText(msg);
       Cu.reportError(msg);
       dumpn(msg);
 
       this.showEditor();
       window.emit(EVENTS.SOURCE_ERROR_SHOWN, source);
       return;
     }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_interrupts.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_interrupts.js
@@ -50,17 +50,17 @@ function test() {
     let onceResumed = gTarget.once("thread-resumed");
     gThreadClient.resume();
     return onceResumed;
   }
 
   function testResumeButton() {
     info ("Pressing the resume button, expecting a thread-paused");
 
-    ok (!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled 1");
+    ok (!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled");
     ok (!gResumeButton.hasAttribute("break-on-next"), "Resume button isn't waiting for next execution");
     ok (!gResumeButton.hasAttribute("checked"), "Resume button is not checked");
     let oncePaused = gTarget.once("thread-paused");
 
     // Click the pause button to break on next execution
     EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger);
     ok (gResumeButton.hasAttribute("disabled"), "Resume button is disabled");
     ok (gResumeButton.hasAttribute("break-on-next"), "Resume button is waiting for next execution");
@@ -70,30 +70,27 @@ function test() {
     once(gDebugger.gClient, "willInterrupt").then(() => {
       evalInTab(gTab, "1+1;");
     });
 
     return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN)
       .then(() => {
         ok (!gResumeButton.hasAttribute("break-on-next"), "Resume button isn't waiting for next execution");
         is (gResumeButton.getAttribute("checked"), "true", "Resume button is checked");
-        ok (!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled 2");
+        ok (!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled");
       })
-      .then(() => {
-        let p = ensureThreadClientState(gPanel, "resumed");
-        gThreadClient.resume();
-        return p;
-      })
+      .then(() => gThreadClient.resume())
+      .then(() => ensureThreadClientState(gPanel, "resumed"))
   }
 
   function testResumeKeyboard() {
     let key = gResumeKey.getAttribute("keycode");
     info ("Triggering a pause with keyboard (" + key +  "), expecting a thread-paused");
 
-    ok (!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled 3");
+    ok (!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled");
     ok (!gResumeButton.hasAttribute("break-on-next"), "Resume button isn't waiting for next execution");
     ok (!gResumeButton.hasAttribute("checked"), "Resume button is not checked");
 
     // Press the key to break on next execution
     EventUtils.synthesizeKey(key, { }, gDebugger);
     ok (gResumeButton.hasAttribute("disabled"), "Resume button is disabled");
     ok (gResumeButton.hasAttribute("break-on-next"), "Resume button is waiting for next execution");
     ok (!gResumeButton.hasAttribute("checked"), "Resume button is not checked");
@@ -102,17 +99,14 @@ function test() {
     once(gDebugger.gClient, "willInterrupt").then(() => {
       evalInTab(gTab, "1+1;");
     });
 
     return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN)
       .then(() => {
         ok (!gResumeButton.hasAttribute("break-on-next"), "Resume button isn't waiting for next execution");
         is (gResumeButton.getAttribute("checked"), "true", "Resume button is checked");
-        ok (!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled 4");
+        ok (!gResumeButton.hasAttribute("disabled"), "Resume button is not disabled");
       })
-      .then(() => {
-        let p = ensureThreadClientState(gPanel, "resumed");
-        gThreadClient.resume();
-        return p;
-      })
+      .then(() => gThreadClient.resume())
+      .then(() => ensureThreadClientState(gPanel, "resumed"))
   }
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_listtabs-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_listtabs-03.js
@@ -4,49 +4,64 @@
 /**
  * Make sure the listTabs request works as specified.
  */
 
 const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
 
 var gTab1, gTab1Actor, gTab2, gTab2Actor, gClient;
 
+function listTabs() {
+  let deferred = promise.defer();
+
+  gClient.listTabs(aResponse => {
+    deferred.resolve(aResponse.tabs);
+  });
+
+  return deferred.promise;
+}
+
+function request(params) {
+  let deferred = promise.defer();
+  gClient.request(params, deferred.resolve);
+  return deferred.promise;
+}
+
 function test() {
   if (!DebuggerServer.initialized) {
     DebuggerServer.init();
     DebuggerServer.addBrowserActors();
   }
 
   let transport = DebuggerServer.connectPipe();
   gClient = new DebuggerClient(transport);
   gClient.connect(Task.async(function*(aType, aTraits) {
     is(aType, "browser",
       "Root actor should identify itself as a browser.");
     let tab = yield addTab(TAB1_URL);
 
-    let { tabs } = yield gClient.listTabs();
+    let tabs = yield listTabs();
     is(tabs.length, 2, "Should be two tabs");
     let tabGrip = tabs.filter(a => a.url ==TAB1_URL).pop();
     ok(tabGrip, "Should have an actor for the tab");
 
-    let response = yield gClient.request({ to: tabGrip.actor, type: "attach" });
+    let response = yield request({ to: tabGrip.actor, type: "attach" });
     is(response.type, "tabAttached", "Should have attached");
 
-    response = yield gClient.listTabs();
-    tabs = response.tabs;
+    tabs = yield listTabs();
 
-    response = yield gClient.request({ to: tabGrip.actor, type: "detach" });
+    response = yield request({ to: tabGrip.actor, type: "detach" });
     is(response.type, "detached", "Should have detached");
 
     let newGrip = tabs.filter(a => a.url ==TAB1_URL).pop();
     is(newGrip.actor, tabGrip.actor, "Should have the same actor for the same tab");
 
-    response = yield gClient.request({ to: tabGrip.actor, type: "attach" });
+    response = yield request({ to: tabGrip.actor, type: "attach" });
     is(response.type, "tabAttached", "Should have attached");
-    response = yield gClient.request({ to: tabGrip.actor, type: "detach" });
+    response = yield request({ to: tabGrip.actor, type: "detach" });
     is(response.type, "detached", "Should have detached");
 
     yield removeTab(tab);
     yield closeConnection();
     finish();
   }));
 }
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-06.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-06.js
@@ -25,17 +25,17 @@ function test() {
     // We can't feed javascript files with syntax errors to the debugger,
     // because they will never run, thus sometimes getting gc'd before the
     // debugger is opened, or even before the target finishes navigating.
     // Make the client lie about being able to parse perfectly fine code.
     gClient.request = (function (aOriginalRequestMethod) {
       return function (aPacket, aCallback) {
         if (aPacket.type == "prettyPrint") {
           gPrettyPrinted = true;
-          return promise.reject({ error: "prettyPrintError" });
+          return executeSoon(() => aCallback({ error: "prettyPrintError" }));
         }
         return aOriginalRequestMethod(aPacket, aCallback);
       };
     }(gClient.request));
 
     Task.spawn(function*() {
       yield waitForSourceShown(gPanel, JS_URL);
 
@@ -49,18 +49,18 @@ function test() {
       ok(gEditor.getText().includes("myFunction"),
         "The source shouldn't be pretty printed yet.");
 
       const source = queries.getSelectedSource(getState());
       try {
         yield actions.togglePrettyPrint(source);
         ok(false, "The promise for a prettified source should be rejected!");
       } catch(error) {
-        ok(error.error, "Error came from a RDP request");
-        ok(error.error.includes("prettyPrintError"),
+        ok(error.rdpError, "Error came from a RDP request");
+        ok(error.rdpError.includes("prettyPrintError"),
           "The promise was correctly rejected with a meaningful message.");
       }
 
       const { text } = yield queries.getSourceText(getState(), source.actor);
       is(getSelectedSourceURL(gSources), JS_URL,
         "The correct source is still selected.");
       ok(gEditor.getText().includes("myFunction"),
         "The displayed source hasn't changed.");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-on-paused.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_pretty-print-on-paused.js
@@ -22,17 +22,17 @@ function test(){
 
     Task.spawn(function* () {
       try {
         yield ensureSourceIs(gPanel, "code_script-switching-02.js", true);
 
         yield doInterrupt(gPanel);
 
         let source = gThreadClient.source(getSourceForm(gSources, SECOND_SOURCE_VALUE));
-        yield source.setBreakpoint({
+        yield rdpInvoke(source, source.setBreakpoint, {
           line: 6
         });
         yield doResume(gPanel);
 
         const bpHit = waitForCaretAndScopes(gPanel, 6);
         callInTab(gTab, "secondCall");
         yield bpHit;
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_scripts-switching-03.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_scripts-switching-03.js
@@ -20,17 +20,17 @@ function test() {
     function showBogusSource() {
       let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_ERROR_SHOWN);
       actions.newSource({ url: "http://example.com/fake.js", actor: "fake.actor" });
       actions.selectSource({ actor: "fake.actor" });
       return finished;
     }
 
     function testDebuggerLoadingError() {
-      ok(gEditor.getText().includes(gL10N.getFormatStr("errorLoadingText2", "No such actor for ID: fake.actor")),
+      ok(gEditor.getText().includes(gL10N.getFormatStr("errorLoadingText2", "noSuchActor")),
          "The valid error loading message is displayed.");
     }
 
     Task.spawn(function*() {
       yield waitForSourceShown(gPanel, "-01.js");
       yield showBogusSource();
       yield testDebuggerLoadingError();
       closeDebuggerAndFinish(gPanel);
--- a/devtools/client/debugger/test/mochitest/head.js
+++ b/devtools/client/debugger/test/mochitest/head.js
@@ -11,16 +11,17 @@ Services.scriptloader.loadSubScript("chr
 var gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
 Services.prefs.setBoolPref("devtools.debugger.log", false);
 
 var { BrowserToolboxProcess } = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
 var { DebuggerServer } = require("devtools/server/main");
 var { DebuggerClient, ObjectClient } = require("devtools/shared/client/main");
 var { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
 var EventEmitter = require("devtools/shared/event-emitter");
+const { promiseInvoke } = require("devtools/shared/async-utils");
 var { Toolbox } = require("devtools/client/framework/toolbox")
 
 // Override promise with deprecated-sync-thenables
 promise = Cu.import("resource://devtools/shared/deprecated-sync-thenables.js", {}).Promise;
 
 const EXAMPLE_URL = "http://example.com/browser/devtools/client/debugger/test/mochitest/";
 const FRAME_SCRIPT_URL = getRootDirectory(gTestPath) + "code_frame-script.js";
 
@@ -881,24 +882,36 @@ function attachAddonActorForUrl(aClient,
     aClient.attachAddon(aGrip.actor, aResponse => {
       deferred.resolve([aGrip, aResponse]);
     });
   });
 
   return deferred.promise;
 }
 
+function rdpInvoke(aClient, aMethod, ...args) {
+  return promiseInvoke(aClient, aMethod, ...args)
+    .then((packet) => {
+      let { error, message } = packet;
+      if (error) {
+        throw new Error(error + ": " + message);
+      }
+
+      return packet;
+    });
+}
+
 function doResume(aPanel) {
   const threadClient = aPanel.panelWin.gThreadClient;
-  return threadClient.resume();
+  return rdpInvoke(threadClient, threadClient.resume);
 }
 
 function doInterrupt(aPanel) {
   const threadClient = aPanel.panelWin.gThreadClient;
-  return threadClient.interrupt();
+  return rdpInvoke(threadClient, threadClient.interrupt);
 }
 
 function pushPrefs(...aPrefs) {
   let deferred = promise.defer();
   SpecialPowers.pushPrefEnv({"set": aPrefs}, deferred.resolve);
   return deferred.promise;
 }
 
@@ -1018,17 +1031,21 @@ function close(client) {
     client.close(() => {
       resolve();
     });
   });
 }
 
 function listTabs(client) {
   info("Listing tabs.");
-  return client.listTabs();
+  return new Promise(function (resolve) {
+    client.listTabs(function (response) {
+      resolve(response);
+    });
+  });
 }
 
 function findTab(tabs, url) {
   info("Finding tab with url '" + url + "'.");
   for (let tab of tabs) {
     if (tab.url === url) {
       return tab;
     }
@@ -1099,17 +1116,17 @@ function waitForWorkerClose(workerClient
       info("Worker did close.");
       resolve();
     });
   });
 }
 
 function resume(threadClient) {
   info("Resuming thread.");
-  return threadClient.resume();
+  return rdpInvoke(threadClient, threadClient.resume);
 }
 
 function findSource(sources, url) {
   info("Finding source with url '" + url + "'.\n");
   for (let source of sources) {
     if (source.url === url) {
       return source;
     }
@@ -1139,22 +1156,22 @@ function waitForEvent(client, type, pred
 
 function waitForPause(threadClient) {
   info("Waiting for pause.\n");
   return waitForEvent(threadClient, "paused");
 }
 
 function setBreakpoint(sourceClient, location) {
   info("Setting breakpoint.\n");
-  return sourceClient.setBreakpoint(location);
+  return rdpInvoke(sourceClient, sourceClient.setBreakpoint, location);
 }
 
 function source(sourceClient) {
   info("Getting source.\n");
-  return sourceClient.source();
+  return rdpInvoke(sourceClient, sourceClient.source);
 }
 
 // Return a promise with a reference to jsterm, opening the split
 // console if necessary.  This cleans up the split console pref so
 // it won't pollute other tests.
 function getSplitConsole(toolbox, win) {
   registerCleanupFunction(() => {
     Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
--- a/devtools/client/framework/connect/connect.js
+++ b/devtools/client/framework/connect/connect.js
@@ -85,17 +85,19 @@ function clientConnect() {
 }
 
 /**
  * Connection is ready. List actors and build buttons.
  */
 var onConnectionReady = Task.async(function*(aType, aTraits) {
   clearTimeout(gConnectionTimeout);
 
-  let response = yield gClient.listAddons();
+  let deferred = promise.defer();
+  gClient.listAddons(deferred.resolve);
+  let response = yield deferred.promise;
 
   let parent = document.getElementById("addonActors")
   if (!response.error && response.addons.length > 0) {
     // Add one entry for each add-on.
     for (let addon of response.addons) {
       if (!addon.debuggable) {
         continue;
       }
@@ -103,17 +105,19 @@ var onConnectionReady = Task.async(funct
     }
   }
   else {
     // Hide the section when there are no add-ons
     parent.previousElementSibling.remove();
     parent.remove();
   }
 
-  response = yield gClient.listTabs();
+  deferred = promise.defer();
+  gClient.listTabs(deferred.resolve);
+  response = yield deferred.promise;
 
   parent = document.getElementById("tabActors");
 
   // Add Global Process debugging...
   let globals = Cu.cloneInto(response, {});
   delete globals.tabs;
   delete globals.selected;
   // ...only if there are appropriate actors (a 'from' property will always
--- a/devtools/client/inspector/markup/test/head.js
+++ b/devtools/client/inspector/markup/test/head.js
@@ -5,16 +5,17 @@
 var Cu = Components.utils;
 var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
 var {TargetFactory} = require("devtools/client/framework/target");
 var {console} = Cu.import("resource://gre/modules/Console.jsm", {});
 var promise = require("promise");
 var {getInplaceEditorForSpan: inplaceEditor} = require("devtools/client/shared/inplace-editor");
 var clipboard = require("sdk/clipboard");
 var {setTimeout, clearTimeout} = require("sdk/timers");
+var {promiseInvoke} = require("devtools/shared/async-utils");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
 // All test are asynchronous
 waitForExplicitFinish();
 
 // If a test times out we want to see the complete log and not just the last few
 // lines.
 SimpleTest.requestCompleteLog();
@@ -757,17 +758,20 @@ function contextMenuClick(element) {
  *
  * - registrar {ActorActor}: A handle to the registered actor that allows
  * unregistration.
  * - form {Object}: The JSON actor form provided by the server.
  */
 function registerTabActor(client, options) {
   let moduleUrl = options.moduleUrl;
 
-  return client.listTabs().then(response => {
+  // Since client.listTabs doesn't use promises we need to
+  // 'promisify' it using 'promiseInvoke' helper method.
+  // This helps us to chain all promises and catch errors.
+  return promiseInvoke(client, client.listTabs).then(response => {
     let config = {
       prefix: options.prefix,
       constructor: options.actorClass,
       type: { tab: true },
     };
 
     // Register the custom actor on the backend.
     let registry = ActorRegistryFront(client, response);
--- a/devtools/client/performance/legacy/front.js
+++ b/devtools/client/performance/legacy/front.js
@@ -351,18 +351,20 @@ const LegacyPerformanceFront = Class({
     if (!this.isRecording()) {
       // This doesn't stop the profiler, just turns off polling for
       // events, and also turns off events on timeline actors.
       yield this._profiler.stop();
       timelineEndTime = yield this._timeline.stop(config);
     }
 
     let systemDeferred = promise.defer();
-    let form = yield this._client.listTabs();
-    let systemHost = yield getDeviceFront(this._client, form).getDescription();
+    this._client.listTabs(form => {
+      systemDeferred.resolve(getDeviceFront(this._client, form).getDescription());
+    });
+    let systemHost = yield systemDeferred.promise;
     let systemClient = yield getSystemInfo();
 
     // Set the results on the LegacyPerformanceRecording itself.
     model._onStopRecording({
       // Data available only at the end of a recording.
       profile: profilerData.profile,
 
       // End times for all the actors.
--- a/devtools/client/performance/test/browser_perf-legacy-front-05.js
+++ b/devtools/client/performance/test/browser_perf-legacy-front-05.js
@@ -20,17 +20,17 @@ function* spawnTest() {
 
   // Ugly, but we need to also not send the startTime to the server
   // so we don't filter it both on the server and client
   let request = target.client.request;
   target.client.request = (data, res) => {
     // Copy so we don't destructively change the request object, as we use
     // the startTime on this object for filtering in the callback
     let newData = merge({}, data, { startTime: void 0 });
-    return request.call(target.client, newData, res);
+    request.call(target.client, newData, res);
   };
 
   // Perform the first recording...
 
   let firstRecording = yield front.startRecording();
   let firstRecordingStartTime = firstRecording._profilerStartTime;
   info("Started profiling at: " + firstRecordingStartTime);
 
--- a/devtools/server/tests/browser/browser_stylesheets_getTextEmpty.js
+++ b/devtools/server/tests/browser/browser_stylesheets_getTextEmpty.js
@@ -15,17 +15,19 @@ add_task(function*() {
   yield addTab(TEST_URI);
 
   info("Initialising the debugger server and client.");
   initDebuggerServer();
   let client = new DebuggerClient(DebuggerServer.connectPipe());
   let form = yield connectDebuggerClient(client);
 
   info("Attaching to the active tab.");
-  yield client.attachTab(form.actor);
+  yield new Promise(resolve => {
+    client.attachTab(form.actor, resolve);
+  });
 
   let front = StyleSheetsFront(client, form);
   ok(front, "The StyleSheetsFront was created.");
 
   let sheets = yield front.getStyleSheets();
   ok(sheets, "getStyleSheets() succeeded");
   is(sheets.length, 1,
      "getStyleSheets() returned the correct number of sheets");
--- a/devtools/server/tests/browser/browser_stylesheets_nested-iframes.js
+++ b/devtools/server/tests/browser/browser_stylesheets_nested-iframes.js
@@ -13,17 +13,19 @@ add_task(function*() {
   let doc = yield addTab(MAIN_DOMAIN + "stylesheets-nested-iframes.html");
 
   info("Initialising the debugger server and client.");
   initDebuggerServer();
   let client = new DebuggerClient(DebuggerServer.connectPipe());
   let form = yield connectDebuggerClient(client);
 
   info("Attaching to the active tab.");
-  yield client.attachTab(form.actor);
+  yield new Promise(resolve => {
+    client.attachTab(form.actor, resolve);
+  });
 
   let front = StyleSheetsFront(client, form);
   ok(front, "The StyleSheetsFront was created.");
 
   let sheets = yield front.getStyleSheets();
   ok(sheets, "getStyleSheets() succeeded even with documentless iframes.");
 
   // Bug 285395 limits the number of nested iframes to 10. There's one sheet per
--- a/devtools/server/tests/mochitest/director-helpers.js
+++ b/devtools/server/tests/mochitest/director-helpers.js
@@ -27,17 +27,17 @@ const {Task} = require("resource://gre/m
  **********************************/
 
 function* newConnectedDebuggerClient(opts) {
   var transport = DebuggerServer.connectPipe();
   var client = new DebuggerClient(transport);
 
   yield promiseInvoke(client, client.connect);
 
-  var root = yield client.listTabs();
+  var root = yield promiseInvoke(client, client.listTabs);
 
   return {
     client: client,
     root: root,
     transport: transport
   };
 }
 
--- a/devtools/server/tests/unit/head_dbg.js
+++ b/devtools/server/tests/unit/head_dbg.js
@@ -7,16 +7,17 @@ var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cr = Components.results;
 var CC = Components.Constructor;
 
 const { require, loader } = Cu.import("resource://devtools/shared/Loader.jsm", {});
 const { worker } = Cu.import("resource://devtools/shared/worker/loader.js", {})
 const promise = require("promise");
 const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
+const { promiseInvoke } = require("devtools/shared/async-utils");
 
 const Services = require("Services");
 // Always log packets when running tests. runxpcshelltests.py will throw
 // the output away anyway, unless you give it the --verbose flag.
 Services.prefs.setBoolPref("devtools.debugger.log", true);
 // Enable remote debugging for the relevant tests.
 Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
 
@@ -143,54 +144,54 @@ function close(client) {
     client.close(function () {
       resolve();
     });
   });
 }
 
 function listTabs(client) {
   dump("Listing tabs.\n");
-  return client.listTabs();
+  return rdpRequest(client, client.listTabs);
 }
 
 function findTab(tabs, title) {
   dump("Finding tab with title '" + title + "'.\n");
   for (let tab of tabs) {
     if (tab.title === title) {
       return tab;
     }
   }
   return null;
 }
 
 function attachTab(client, tab) {
   dump("Attaching to tab with title '" + tab.title + "'.\n");
-  return client.attachTab(tab.actor);
+  return rdpRequest(client, client.attachTab, tab.actor);
 }
 
 function waitForNewSource(threadClient, url) {
   dump("Waiting for new source with url '" + url + "'.\n");
   return waitForEvent(threadClient, "newSource", function (packet) {
     return packet.source.url === url;
   });
 }
 
 function attachThread(tabClient, options = {}) {
   dump("Attaching to thread.\n");
-  return tabClient.attachThread(options);
+  return rdpRequest(tabClient, tabClient.attachThread, options);
 }
 
 function resume(threadClient) {
   dump("Resuming thread.\n");
-  return threadClient.resume();
+  return rdpRequest(threadClient, threadClient.resume);
 }
 
 function getSources(threadClient) {
   dump("Getting sources.\n");
-  return threadClient.getSources();
+  return rdpRequest(threadClient, threadClient.getSources);
 }
 
 function findSource(sources, url) {
   dump("Finding source with url '" + url + "'.\n");
   for (let source of sources) {
     if (source.url === url) {
       return source;
     }
@@ -200,17 +201,17 @@ function findSource(sources, url) {
 
 function waitForPause(threadClient) {
   dump("Waiting for pause.\n");
   return waitForEvent(threadClient, "paused");
 }
 
 function setBreakpoint(sourceClient, location) {
   dump("Setting breakpoint.\n");
-  return sourceClient.setBreakpoint(location);
+  return rdpRequest(sourceClient, sourceClient.setBreakpoint, location);
 }
 
 function dumpn(msg) {
   dump("DBG-TEST: " + msg + "\n");
 }
 
 function tryImport(url) {
   try {
@@ -684,24 +685,48 @@ function waitForEvent(client, type, pred
  */
 function executeOnNextTickAndWaitForPause(action, client) {
   const paused = waitForPause(client);
   executeSoon(action);
   return paused;
 }
 
 /**
+ * Create a promise that is resolved with the server's response to the client's
+ * Remote Debugger Protocol request. If a response with the `error` property is
+ * received, the promise is rejected. Any extra arguments passed in are
+ * forwarded to the method invocation.
+ *
+ * See `setBreakpoint` below, for example usage.
+ *
+ * @param DebuggerClient/ThreadClient/SourceClient/etc client
+ * @param Function method
+ * @param any args
+ * @returns Promise
+ */
+function rdpRequest(client, method, ...args) {
+  return promiseInvoke(client, method, ...args)
+    .then(response => {
+      const { error, message } = response;
+      if (error) {
+        throw new Error(error + ": " + message);
+      }
+      return response;
+    });
+}
+
+/**
  * Interrupt JS execution for the specified thread.
  *
  * @param ThreadClient threadClient
  * @returns Promise
  */
 function interrupt(threadClient) {
   dumpn("Interrupting.");
-  return threadClient.interrupt();
+  return rdpRequest(threadClient, threadClient.interrupt);
 }
 
 /**
  * Resume JS execution for the specified thread and then wait for the next pause
  * event.
  *
  * @param DebuggerClient client
  * @param ThreadClient threadClient
@@ -718,17 +743,17 @@ function resumeAndWaitForPause(client, t
  *
  * @param DebuggerClient client
  * @param ThreadClient threadClient
  * @returns Promise
  */
 function stepIn(client, threadClient) {
   dumpn("Stepping in.");
   const paused = waitForPause(client);
-  return threadClient.stepIn()
+  return rdpRequest(threadClient, threadClient.stepIn)
     .then(() => paused);
 }
 
 /**
  * Resume JS execution for a step over and wait for the pause after the step
  * has been taken.
  *
  * @param DebuggerClient client
@@ -748,51 +773,51 @@ function stepOver(client, threadClient) 
  *
  * @param ThreadClient threadClient
  * @param Number first
  * @param Number count
  * @returns Promise
  */
 function getFrames(threadClient, first, count) {
   dumpn("Getting frames.");
-  return threadClient.getFrames(first, count);
+  return rdpRequest(threadClient, threadClient.getFrames, first, count);
 }
 
 /**
  * Black box the specified source.
  *
  * @param SourceClient sourceClient
  * @returns Promise
  */
 function blackBox(sourceClient) {
   dumpn("Black boxing source: " + sourceClient.actor);
-  return sourceClient.blackBox();
+  return rdpRequest(sourceClient, sourceClient.blackBox);
 }
 
 /**
  * Stop black boxing the specified source.
  *
  * @param SourceClient sourceClient
  * @returns Promise
  */
 function unBlackBox(sourceClient) {
   dumpn("Un-black boxing source: " + sourceClient.actor);
-  return sourceClient.unblackBox();
+  return rdpRequest(sourceClient, sourceClient.unblackBox);
 }
 
 /**
  * Perform a "source" RDP request with the given SourceClient to get the source
  * content and content type.
  *
  * @param SourceClient sourceClient
  * @returns Promise
  */
 function getSourceContent(sourceClient) {
   dumpn("Getting source content for " + sourceClient.actor);
-  return sourceClient.source();
+  return rdpRequest(sourceClient, sourceClient.source);
 }
 
 /**
  * Get a source at the specified url.
  *
  * @param ThreadClient threadClient
  * @param string url
  * @returns Promise<SourceClient>
--- a/devtools/shared/client/main.js
+++ b/devtools/shared/client/main.js
@@ -442,48 +442,46 @@ DebuggerClient.prototype = {
       DevToolsUtils.executeSoon(() => aOnResponse(cachedResponse, cachedTab));
       return;
     }
 
     let packet = {
       to: aTabActor,
       type: "attach"
     };
-    return this.request(packet).then(aResponse => {
+    this.request(packet, (aResponse) => {
       let tabClient;
       if (!aResponse.error) {
         tabClient = new TabClient(this, aResponse);
         this.registerClient(tabClient);
       }
       aOnResponse(aResponse, tabClient);
-      return [aResponse, tabClient];
     });
   },
 
   attachWorker: function DC_attachWorker(aWorkerActor, aOnResponse = noop) {
     let workerClient = this._clients.get(aWorkerActor);
     if (workerClient !== undefined) {
       DevToolsUtils.executeSoon(() => aOnResponse({
         from: workerClient.actor,
         type: "attached",
         url: workerClient.url
       }, workerClient));
       return;
     }
 
-    return this.request({ to: aWorkerActor, type: "attach" }).then(aResponse => {
+    this.request({ to: aWorkerActor, type: "attach" }, (aResponse) => {
       if (aResponse.error) {
         aOnResponse(aResponse, null);
-        return [aResponse, null];
+        return;
       }
 
       let workerClient = new WorkerClient(this, aResponse);
       this.registerClient(workerClient);
       aOnResponse(aResponse, workerClient);
-      return [aResponse, workerClient];
     });
   },
 
   /**
    * Attach to an addon actor.
    *
    * @param string aAddonActor
    *        The actor ID for the addon to attach.
@@ -491,25 +489,24 @@ DebuggerClient.prototype = {
    *        Called with the response packet and a AddonClient
    *        (which will be undefined on error).
    */
   attachAddon: function DC_attachAddon(aAddonActor, aOnResponse = noop) {
     let packet = {
       to: aAddonActor,
       type: "attach"
     };
-    return this.request(packet).then(aResponse => {
+    this.request(packet, aResponse => {
       let addonClient;
       if (!aResponse.error) {
         addonClient = new AddonClient(this, aAddonActor);
         this.registerClient(addonClient);
         this.activeAddon = addonClient;
       }
       aOnResponse(aResponse, addonClient);
-      return [aResponse, addonClient];
     });
   },
 
   /**
    * Attach to a Web Console actor.
    *
    * @param string aConsoleActor
    *        The ID for the console actor to attach to.
@@ -522,28 +519,27 @@ DebuggerClient.prototype = {
   attachConsole:
   function (aConsoleActor, aListeners, aOnResponse = noop) {
     let packet = {
       to: aConsoleActor,
       type: "startListeners",
       listeners: aListeners,
     };
 
-    return this.request(packet).then(aResponse => {
+    this.request(packet, (aResponse) => {
       let consoleClient;
       if (!aResponse.error) {
         if (this._clients.has(aConsoleActor)) {
           consoleClient = this._clients.get(aConsoleActor);
         } else {
           consoleClient = new WebConsoleClient(this, aResponse);
           this.registerClient(consoleClient);
         }
       }
       aOnResponse(aResponse, consoleClient);
-      return [aResponse, consoleClient];
     });
   },
 
   /**
    * Attach to a global-scoped thread actor for chrome debugging.
    *
    * @param string aThreadActor
    *        The actor ID for the thread to attach.
@@ -555,28 +551,27 @@ DebuggerClient.prototype = {
    *        - useSourceMaps: whether to use source maps or not.
    */
   attachThread: function (aThreadActor, aOnResponse = noop, aOptions={}) {
     if (this._clients.has(aThreadActor)) {
       DevToolsUtils.executeSoon(() => aOnResponse({}, this._clients.get(aThreadActor)));
       return;
     }
 
-    let packet = {
+   let packet = {
       to: aThreadActor,
       type: "attach",
       options: aOptions
     };
-    return this.request(packet).then(aResponse => {
+    this.request(packet, (aResponse) => {
       if (!aResponse.error) {
         var threadClient = new ThreadClient(this, aThreadActor);
         this.registerClient(threadClient);
       }
       aOnResponse(aResponse, threadClient);
-      return [aResponse, threadClient];
     });
   },
 
   /**
    * Attach to a trace actor.
    *
    * @param string aTraceActor
    *        The actor ID for the tracer to attach.
@@ -589,23 +584,22 @@ DebuggerClient.prototype = {
       DevToolsUtils.executeSoon(() => aOnResponse({}, this._clients.get(aTraceActor)));
       return;
     }
 
     let packet = {
       to: aTraceActor,
       type: "attach"
     };
-    return this.request(packet).then(aResponse => {
+    this.request(packet, (aResponse) => {
       if (!aResponse.error) {
         var traceClient = new TraceClient(this, aTraceActor);
         this.registerClient(traceClient);
       }
       aOnResponse(aResponse, traceClient);
-      return [aResponse, traceClient];
     });
   },
 
   /**
    * Fetch the ChromeActor for the main process or ChildProcessActor for a
    * a given child process ID.
    *
    * @param number aId
@@ -1264,23 +1258,22 @@ TabClient.prototype = {
       return;
     }
 
     let packet = {
       to: this._threadActor,
       type: "attach",
       options: aOptions
     };
-    return this.request(packet).then(aResponse => {
+    this.request(packet, (aResponse) => {
       if (!aResponse.error) {
         this.thread = new ThreadClient(this, this._threadActor);
         this.client.registerClient(this.thread);
       }
       aOnResponse(aResponse, this.thread);
-      return [aResponse, this.thread];
     });
   },
 
   /**
    * Detach the client from the tab actor.
    *
    * @param function aOnResponse
    *        Called with the response packet.
@@ -1399,50 +1392,48 @@ WorkerClient.prototype = {
       return aResponse;
     },
 
     telemetry: "WORKERDETACH"
   }),
 
   attachThread: function(aOptions = {}, aOnResponse = noop) {
     if (this.thread) {
-      let response = [{
+      DevToolsUtils.executeSoon(() => aOnResponse({
         type: "connected",
         threadActor: this.thread._actor,
         consoleActor: this.consoleActor,
-      }, this.thread];
-      DevToolsUtils.executeSoon(() => aOnResponse(response));
-      return response;
+      }, this.thread));
+      return;
     }
 
     // The connect call on server doesn't attach the thread as of version 44.
-    return this.request({
+    this.request({
       to: this._actor,
       type: "connect",
       options: aOptions,
-    }).then(connectReponse => {
+    }, (connectReponse) => {
       if (connectReponse.error) {
         aOnResponse(connectReponse, null);
-        return [connectResponse, null];
+        return;
       }
 
-      return this.request({
+      this.request({
         to: connectReponse.threadActor,
         type: "attach"
-      }).then(attachResponse => {
+      }, (attachResponse) => {
         if (attachResponse.error) {
           aOnResponse(attachResponse, null);
         }
 
         this.thread = new ThreadClient(this, connectReponse.threadActor);
         this.consoleActor = connectReponse.consoleActor;
         this.client.registerClient(this.thread);
 
         aOnResponse(connectReponse, this.thread);
-        return [connectResponse, this.thread];
       });
     });
   },
 
   _onClose: function () {
     this.removeListener("close", this._onClose);
 
     if (this.thread) {
@@ -1729,77 +1720,77 @@ ThreadClient.prototype = {
   }, {
     telemetry: "RECONFIGURETHREAD"
   }),
 
   /**
    * Resume a paused thread.
    */
   resume: function (aOnResponse) {
-    return this._doResume(null, aOnResponse);
+    this._doResume(null, aOnResponse);
   },
 
   /**
    * Resume then pause without stepping.
    *
    * @param function aOnResponse
    *        Called with the response packet.
    */
   resumeThenPause: function (aOnResponse) {
-    return this._doResume({ type: "break" }, aOnResponse);
+    this._doResume({ type: "break" }, aOnResponse);
   },
 
   /**
    * Step over a function call.
    *
    * @param function aOnResponse
    *        Called with the response packet.
    */
   stepOver: function (aOnResponse) {
-    return this._doResume({ type: "next" }, aOnResponse);
+    this._doResume({ type: "next" }, aOnResponse);
   },
 
   /**
    * Step into a function call.
    *
    * @param function aOnResponse
    *        Called with the response packet.
    */
   stepIn: function (aOnResponse) {
-    return this._doResume({ type: "step" }, aOnResponse);
+    this._doResume({ type: "step" }, aOnResponse);
   },
 
   /**
    * Step out of a function call.
    *
    * @param function aOnResponse
    *        Called with the response packet.
    */
   stepOut: function (aOnResponse) {
-    return this._doResume({ type: "finish" }, aOnResponse);
+    this._doResume({ type: "finish" }, aOnResponse);
   },
 
   /**
    * Immediately interrupt a running thread.
    *
    * @param function aOnResponse
    *        Called with the response packet.
    */
   interrupt: function(aOnResponse) {
-    return this._doInterrupt(null, aOnResponse);
+    this._doInterrupt(null, aOnResponse);
   },
 
   /**
    * Pause execution right before the next JavaScript bytecode is executed.
    *
    * @param function aOnResponse
    *        Called with the response packet.
    */
   breakOnNext: function(aOnResponse) {
-    return this._doInterrupt("onNext", aOnResponse);
+    this._doInterrupt("onNext", aOnResponse);
   },
 
   /**
    * Interrupt a running thread.
    *
    * @param function aOnResponse
    *        Called with the response packet.
    */
@@ -1829,23 +1820,23 @@ ThreadClient.prototype = {
     if (this.paused) {
       this.reconfigure({
         pauseOnExceptions: aPauseOnExceptions,
         ignoreCaughtExceptions: aIgnoreCaughtExceptions
       }, aOnResponse);
       return;
     }
     // Otherwise send the flag using a standard resume request.
-    return this.interrupt(aResponse => {
+    this.interrupt(aResponse => {
       if (aResponse.error) {
         // Can't continue if pausing failed.
         aOnResponse(aResponse);
-        return aResponse;
+        return;
       }
-      return this.resume(aOnResponse);
+      this.resume(aOnResponse);
     });
   },
 
   /**
    * Enable pausing when the specified DOM events are triggered. Disabling
    * pausing on an event can be realized by calling this method with the updated
    * array of events that doesn't contain it.
    *
@@ -1858,25 +1849,25 @@ ThreadClient.prototype = {
    */
   pauseOnDOMEvents: function (events, onResponse = noop) {
     this._pauseOnDOMEvents = events;
     // If the debuggee is paused, the value of the array will be communicated in
     // the next resumption. Otherwise we have to force a pause in order to send
     // the array.
     if (this.paused) {
       DevToolsUtils.executeSoon(() => onResponse({}));
-      return {};
+      return;
     }
-    return this.interrupt(response => {
+    this.interrupt(response => {
       // Can't continue if pausing failed.
       if (response.error) {
         onResponse(response);
-        return response;
+        return;
       }
-      return this.resume(onResponse);
+      this.resume(onResponse);
     });
   },
 
   /**
    * Send a clientEvaluate packet to the debuggee. Response
    * will be a resume packet.
    *
    * @param string aFrame
@@ -2753,103 +2744,100 @@ SourceClient.prototype = {
   }),
 
   /**
    * Get Executable Lines from a source
    *
    * @param aCallback Function
    *        The callback function called when we receive the response from the server.
    */
-  getExecutableLines: function(cb = noop){
+  getExecutableLines: function(cb){
     let packet = {
       to: this._form.actor,
       type: "getExecutableLines"
     };
 
-    return this._client.request(packet).then(res => {
+    this._client.request(packet, res => {
       cb(res.lines);
-      return res.lines;
     });
   },
 
   /**
    * Get a long string grip for this SourceClient's source.
    */
-  source: function (aCallback = noop) {
+  source: function (aCallback) {
     let packet = {
       to: this._form.actor,
       type: "source"
     };
-    return this._client.request(packet).then(aResponse => {
-      return this._onSourceResponse(aResponse, aCallback)
+    this._client.request(packet, aResponse => {
+      this._onSourceResponse(aResponse, aCallback)
     });
   },
 
   /**
    * Pretty print this source's text.
    */
-  prettyPrint: function (aIndent, aCallback = noop) {
+  prettyPrint: function (aIndent, aCallback) {
     const packet = {
       to: this._form.actor,
       type: "prettyPrint",
       indent: aIndent
     };
-    return this._client.request(packet).then(aResponse => {
+    this._client.request(packet, aResponse => {
       if (!aResponse.error) {
         this._isPrettyPrinted = true;
         this._activeThread._clearFrames();
         this._activeThread.emit("prettyprintchange", this);
       }
-      return this._onSourceResponse(aResponse, aCallback);
+      this._onSourceResponse(aResponse, aCallback);
     });
   },
 
   /**
    * Stop pretty printing this source's text.
    */
-  disablePrettyPrint: function (aCallback = noop) {
+  disablePrettyPrint: function (aCallback) {
     const packet = {
       to: this._form.actor,
       type: "disablePrettyPrint"
     };
-    return this._client.request(packet).then(aResponse => {
+    this._client.request(packet, aResponse => {
       if (!aResponse.error) {
         this._isPrettyPrinted = false;
         this._activeThread._clearFrames();
         this._activeThread.emit("prettyprintchange", this);
       }
-      return this._onSourceResponse(aResponse, aCallback);
+      this._onSourceResponse(aResponse, aCallback);
     });
   },
 
   _onSourceResponse: function (aResponse, aCallback) {
     if (aResponse.error) {
       aCallback(aResponse);
-      return aResponse;
+      return;
     }
 
     if (typeof aResponse.source === "string") {
       aCallback(aResponse);
-      return aResponse;
+      return;
     }
 
     let { contentType, source } = aResponse;
     let longString = this._activeThread.threadLongString(source);
-    return longString.substring(0, longString.length).then(function (aResponse) {
+    longString.substring(0, longString.length, function (aResponse) {
       if (aResponse.error) {
         aCallback(aResponse);
-        return aReponse;
+        return;
       }
 
-      let response = {
+      aCallback({
         source: aResponse.substring,
         contentType: contentType
-      };
-      aCallback(response);
-      return response;
+      });
     });
   },
 
   /**
    * Request to set a breakpoint in the specified location.
    *
    * @param object aLocation
    *        The location and condition of the breakpoint in
@@ -2875,56 +2863,56 @@ SourceClient.prototype = {
 
       // Backwards compatibility: send the breakpoint request to the
       // thread if the server doesn't support Debugger.Source actors.
       if (!root.traits.debuggerSourceActors) {
         packet.to = this._activeThread.actor;
         packet.location.url = this.url;
       }
 
-      return this._client.request(packet).then(aResponse => {
+      this._client.request(packet, aResponse => {
         // Ignoring errors, since the user may be setting a breakpoint in a
         // dead script that will reappear on a page reload.
         let bpClient;
         if (aResponse.actor) {
           bpClient = new BreakpointClient(
             this._client,
             this,
             aResponse.actor,
             location,
             root.traits.conditionalBreakpoints ? condition : undefined
           );
         }
         aOnResponse(aResponse, bpClient);
         if (aCallback) {
           aCallback();
         }
-        return [aResponse, bpClient];
       });
     };
 
     // If the debuggee is paused, just set the breakpoint.
     if (this._activeThread.paused) {
-      return doSetBreakpoint();
+      doSetBreakpoint();
+      return;
     }
     // Otherwise, force a pause in order to set the breakpoint.
-    return this._activeThread.interrupt().then(aResponse => {
+    this._activeThread.interrupt(aResponse => {
       if (aResponse.error) {
         // Can't set the breakpoint if pausing failed.
         aOnResponse(aResponse);
-        return aResponse;
+        return;
       }
 
       const { type, why } = aResponse;
       const cleanUp = type == "paused" && why.type == "interrupted"
             ? () => this._activeThread.resume()
             : noop;
 
-      return doSetBreakpoint(cleanUp);
-    });
+      doSetBreakpoint(cleanUp);
+    })
   }
 };
 
 /**
  * Breakpoint clients are used to remove breakpoints that are no longer used.
  *
  * @param aClient DebuggerClient
  *        The debugger client parent.