Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 17 Apr 2015 15:44:37 -0400
changeset 269572 a55f9bdb2bf4f8f6bf4119037386a4409345bc83
parent 269446 1997fbfa8a8ff3f1ecec6a58cd55c6bb6c29b61a (current diff)
parent 269571 10b09c1932142eba1049396720d3a6d36a9418ea (diff)
child 269573 fff4d44e1f41b0674819f9f06cc8727a9ed6ec23
push id4830
push userjlund@mozilla.com
push dateMon, 29 Jun 2015 20:18:48 +0000
treeherdermozilla-beta@4c2175bb0420 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone40.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
Merge inbound to m-c. a=merge
CLOBBER
dom/base/nsGkAtomList.h
dom/cache/CacheInitData.ipdlh
dom/cache/PCacheTypes.ipdlh
dom/cache/StreamUtils.cpp
dom/cache/StreamUtils.h
dom/fetch/FetchIPCUtils.h
dom/fetch/PHeaders.ipdlh
dom/ipc/ContentChild.cpp
media/libvpx/vp8/common/arm/neon/copymem_neon.c
media/libvpx/vp8/common/arm/neon/dc_only_idct_add_neon.c
media/libvpx/vp8/common/arm/neon/dequant_idct_neon.c
media/libvpx/vp8/common/arm/neon/dequantizeb_neon.c
media/libvpx/vp8/common/arm/neon/idct_dequant_0_2x_neon.c
media/libvpx/vp8/common/arm/neon/idct_dequant_full_2x_neon.c
media/libvpx/vp8/common/arm/neon/iwalsh_neon.c
media/libvpx/vp8/common/arm/neon/loopfilter_neon.c
media/libvpx/vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.c
media/libvpx/vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.c
media/libvpx/vp8/common/arm/neon/mbloopfilter_neon.c
media/libvpx/vp8/common/arm/neon/reconintra_neon.c
media/libvpx/vp8/common/arm/neon/sad_neon.c
media/libvpx/vp8/common/arm/neon/shortidct4x4llm_neon.c
media/libvpx/vp8/common/arm/neon/sixtappredict_neon.c
media/libvpx/vp8/common/arm/neon/variance_neon.c
media/libvpx/vp8/common/arm/neon/vp8_subpixelvariance_neon.c
media/libvpx/vp8/common/x86/loopfilter_block_sse2_x86_64.asm
media/libvpx/vp8/encoder/arm/neon/shortfdct_neon.c
media/libvpx/vp8/encoder/arm/neon/subtract_neon.c
media/libvpx/vp8/encoder/arm/neon/vp8_mse16x16_neon.c
media/libvpx/vp8/encoder/arm/neon/vp8_shortwalsh4x4_neon.c
media/libvpx/vp8/encoder/x86/quantize_sse4.c
media/libvpx/vp8/encoder/x86/quantize_ssse3.c
media/libvpx/vp8/encoder/x86/ssim_opt_x86_64.asm
media/libvpx/vp9/common/vp9_thread.c
media/libvpx/vp9/common/vp9_thread.h
media/libvpx/vp9/common/x86/vp9_high_intrapred_sse2.asm
media/libvpx/vp9/common/x86/vp9_high_loopfilter_intrin_sse2.c
media/libvpx/vp9/common/x86/vp9_high_subpixel_8t_sse2.asm
media/libvpx/vp9/common/x86/vp9_high_subpixel_bilinear_sse2.asm
media/libvpx/vp9/common/x86/vp9_idct_intrin_sse2.h
media/libvpx/vp9/common/x86/vp9_idct_intrin_ssse3.c
media/libvpx/vp9/common/x86/vp9_idct_ssse3_x86_64.asm
media/libvpx/vp9/common/x86/vp9_subpixel_8t_intrin_ssse3.c
media/libvpx/vp9/decoder/vp9_decoder.c
media/libvpx/vp9/decoder/vp9_decoder.h
media/libvpx/vp9/decoder/vp9_read_bit_buffer.c
media/libvpx/vp9/encoder/arm/neon/vp9_dct_neon.c
media/libvpx/vp9/encoder/arm/neon/vp9_quantize_neon.c
media/libvpx/vp9/encoder/arm/neon/vp9_sad_neon.c
media/libvpx/vp9/encoder/arm/neon/vp9_subtract_neon.c
media/libvpx/vp9/encoder/arm/neon/vp9_variance_neon.c
media/libvpx/vp9/encoder/vp9_aq_complexity.c
media/libvpx/vp9/encoder/vp9_aq_complexity.h
media/libvpx/vp9/encoder/vp9_aq_cyclicrefresh.c
media/libvpx/vp9/encoder/vp9_aq_cyclicrefresh.h
media/libvpx/vp9/encoder/vp9_aq_variance.c
media/libvpx/vp9/encoder/vp9_aq_variance.h
media/libvpx/vp9/encoder/vp9_context_tree.c
media/libvpx/vp9/encoder/vp9_context_tree.h
media/libvpx/vp9/encoder/vp9_cost.c
media/libvpx/vp9/encoder/vp9_cost.h
media/libvpx/vp9/encoder/vp9_denoiser.c
media/libvpx/vp9/encoder/vp9_denoiser.h
media/libvpx/vp9/encoder/vp9_encoder.c
media/libvpx/vp9/encoder/vp9_encoder.h
media/libvpx/vp9/encoder/vp9_rd.c
media/libvpx/vp9/encoder/vp9_rd.h
media/libvpx/vp9/encoder/vp9_speed_features.c
media/libvpx/vp9/encoder/vp9_speed_features.h
media/libvpx/vp9/encoder/vp9_ssim.h
media/libvpx/vp9/encoder/vp9_svc_layercontext.c
media/libvpx/vp9/encoder/vp9_svc_layercontext.h
media/libvpx/vp9/encoder/vp9_write_bit_buffer.c
media/libvpx/vp9/encoder/x86/vp9_dct_mmx.asm
media/libvpx/vp9/encoder/x86/vp9_dct_ssse3_x86_64.asm
media/libvpx/vp9/encoder/x86/vp9_error_intrin_avx2.c
media/libvpx/vp9/encoder/x86/vp9_quantize_ssse3_x86_64.asm
media/libvpx/vp9/encoder/x86/vp9_sad4d_intrin_avx2.c
media/libvpx/vp9/encoder/x86/vp9_ssim_opt_x86_64.asm
media/libvpx/vp9/encoder/x86/vp9_subpel_variance_impl_intrin_avx2.c
media/libvpx/vpx/internal/vpx_psnr.h
media/libvpx/vpx/src/vpx_psnr.c
modules/libpref/init/all.js
testing/web-platform/meta/service-workers/cache-storage/window/cache-storage-keys.https.html.ini
toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,13 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1155082: Merge BluetoothUUID.{cpp,h} variants into single file
-
-This patch set renames and removes source files. This requires updating
-the build system's dependency information from scratch. The issue has
-been reported in bug 1154232.
+Bug 1148639 - libvpx update moved a bunch of files around.
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -282,16 +282,17 @@ skip-if = buildapp == "mulet" || e10s # 
 [browser_bug970746.js]
 skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and gets in a mess when in e10s mode
 [browser_bug1015721.js]
 skip-if = os == 'win' || e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
 [browser_bug1064280_changeUrlInPinnedTab.js]
 [browser_bug1070778.js]
 [browser_canonizeURL.js]
 skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
+[browser_clipboard.js]
 [browser_contentAreaClick.js]
 [browser_contextSearchTabPosition.js]
 skip-if = os == "mac" || e10s # bug 967013; e10s: bug 1094761 - test hits the network in e10s, causing next test to crash
 [browser_ctrlTab.js]
 [browser_datareporting_notification.js]
 skip-if = !datareporting
 [browser_devedition.js]
 [browser_devices_get_user_media.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_clipboard.js
@@ -0,0 +1,123 @@
+// This test is used to check copy and paste in editable areas to ensure that non-text
+// types (html and images) are copied to and pasted from the clipboard properly.
+
+let testPage = "<div id='main' contenteditable='true'>Test <b>Bold</b> After Text</div>";
+
+add_task(function*() {
+  let tab = gBrowser.addTab();
+  let browser = gBrowser.getBrowserForTab(tab);
+
+  gBrowser.selectedTab = tab;
+
+  yield promiseTabLoadEvent(tab, "data:text/html," + escape(testPage));
+  yield SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
+
+  let results = yield ContentTask.spawn(browser, {}, function* () {
+    var doc = content.document;
+    var main = doc.getElementById("main");
+    main.focus();
+
+    const utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                         .getInterface(Components.interfaces.nsIDOMWindowUtils);
+
+    const modifier = (content.navigator.platform.indexOf("Mac") >= 0) ?
+                     Components.interfaces.nsIDOMWindowUtils.MODIFIER_META :
+                     Components.interfaces.nsIDOMWindowUtils.MODIFIER_CONTROL;
+
+    function sendKey(key)
+    {
+     if (utils.sendKeyEvent("keydown", key, 0, modifier)) {
+       utils.sendKeyEvent("keypress", key, key.charCodeAt(0), modifier);
+     }
+     utils.sendKeyEvent("keyup", key, 0, modifier);
+    }
+
+    let results = [];
+    function is(l, r, v) {
+      results.push(((l === r) ? "PASSED" : "FAILED") + " got: " + l + " expected: " + r + " - " + v);
+    }
+
+    // Select an area of the text.
+    let selection = doc.getSelection();
+    selection.modify("move", "left", "line");
+    selection.modify("move", "right", "character");
+    selection.modify("move", "right", "character");
+    selection.modify("move", "right", "character");
+    selection.modify("extend", "right", "word");
+    selection.modify("extend", "right", "word");
+
+    yield new content.Promise((resolve, reject) => {
+      addEventListener("copy", function copyEvent(event) {
+        removeEventListener("copy", copyEvent, true);
+        // The data is empty as the selection is copied during the event default phase.
+        is(event.clipboardData.mozItemCount, 0, "Zero items on clipboard");
+        resolve();
+      }, true)
+
+      sendKey("c");
+    });
+
+    selection.modify("move", "right", "line");
+
+    yield new content.Promise((resolve, reject) => {
+      addEventListener("paste", function copyEvent(event) {
+        removeEventListener("paste", copyEvent, true);
+        let clipboardData = event.clipboardData; 
+        is(clipboardData.mozItemCount, 1, "One item on clipboard");
+        is(clipboardData.types.length, 2, "Two types on clipboard");
+        is(clipboardData.types[0], "text/html", "text/html on clipboard");
+        is(clipboardData.types[1], "text/plain", "text/plain on clipboard");
+        is(clipboardData.getData("text/html"), "t <b>Bold</b>", "text/html value");
+        is(clipboardData.getData("text/plain"), "t Bold", "text/plain value");
+        resolve();
+      }, true)
+      sendKey("v");
+    });
+
+    is(main.innerHTML, "Test <b>Bold</b> After Textt <b>Bold</b>", "Copy and paste html");
+
+    selection.modify("extend", "left", "word");
+    selection.modify("extend", "left", "word");
+    selection.modify("extend", "left", "character");
+
+    yield new content.Promise((resolve, reject) => {
+      addEventListener("cut", function copyEvent(event) {
+        removeEventListener("cut", copyEvent, true);
+        event.clipboardData.setData("text/plain", "Some text");
+        event.clipboardData.setData("text/html", "<i>Italic</i> ");
+        selection.deleteFromDocument();
+        event.preventDefault();
+        resolve();
+      }, true)
+      sendKey("x");
+    });
+
+    selection.modify("move", "left", "line");
+
+    yield new content.Promise((resolve, reject) => {
+      addEventListener("paste", function copyEvent(event) {
+        removeEventListener("paste", copyEvent, true);
+        let clipboardData = event.clipboardData; 
+        is(clipboardData.mozItemCount, 1, "One item on clipboard 2");
+        is(clipboardData.types.length, 2, "Two types on clipboard 2");
+        is(clipboardData.types[0], "text/html", "text/html on clipboard 2");
+        is(clipboardData.types[1], "text/plain", "text/plain on clipboard 2");
+        is(clipboardData.getData("text/html"), "<i>Italic</i> ", "text/html value 2");
+        is(clipboardData.getData("text/plain"), "Some text", "text/plain value 2");
+        resolve();
+      }, true)
+      sendKey("v");
+    });
+
+    is(main.innerHTML, "<i>Italic</i> Test <b>Bold</b> After<b></b>", "Copy and paste html 2");
+    return results;
+  });
+
+  is(results.length, 15, "Correct number of results");
+  for (var t = 0; t < results.length; t++) {
+    ok(results[t].startsWith("PASSED"), results[t]);
+  }
+
+  gBrowser.removeCurrentTab();
+});
+
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -241,17 +241,17 @@ var gAdvancedPane = {
   setTelemetrySectionEnabled: function (aEnabled)
   {
 #ifdef MOZ_TELEMETRY_REPORTING
     // If FHR is disabled, additional data sharing should be disabled as well.
     let disabled = !aEnabled;
     document.getElementById("submitTelemetryBox").disabled = disabled;
     if (disabled) {
       // If we disable FHR, untick the telemetry checkbox.
-      document.getElementById("submitTelemetryBox").checked = false;
+      Services.prefs.setBoolPref("toolkit.telemetry.enabled", false);
     }
     document.getElementById("telemetryDataDesc").disabled = disabled;
 #endif
   },
 
 #ifdef MOZ_SERVICES_HEALTHREPORT
   /**
    * Initialize the health report service reference and checkbox.
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -270,17 +270,17 @@ var gAdvancedPane = {
   setTelemetrySectionEnabled: function (aEnabled)
   {
 #ifdef MOZ_TELEMETRY_REPORTING
     // If FHR is disabled, additional data sharing should be disabled as well.
     let disabled = !aEnabled;
     document.getElementById("submitTelemetryBox").disabled = disabled;
     if (disabled) {
       // If we disable FHR, untick the telemetry checkbox.
-      document.getElementById("submitTelemetryBox").checked = false;
+      Services.prefs.setBoolPref("toolkit.telemetry.enabled", false);
     }
     document.getElementById("telemetryDataDesc").disabled = disabled;
 #endif
   },
 
 #ifdef MOZ_SERVICES_HEALTHREPORT
   /**
    * Initialize the health report service reference and checkbox.
--- a/browser/components/preferences/in-content/tests/browser_telemetry.js
+++ b/browser/components/preferences/in-content/tests/browser_telemetry.js
@@ -1,13 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
+
 function runPaneTest(fn) {
   open_preferences((win) => {
     let doc = win.document;
     win.gotoPref("paneAdvanced");
     let advancedPrefs = doc.getElementById("advancedPrefs");
     let tab = doc.getElementById("dataChoicesTab");
     advancedPrefs.selectedTab = tab;
     fn(win, doc);
@@ -23,23 +25,28 @@ function test() {
 
 function testTelemetryState(win, doc) {
   let fhrCheckbox = doc.getElementById("submitHealthReportBox");
   Assert.ok(fhrCheckbox.checked, "Health Report checkbox is checked on app first run.");
 
   let telmetryCheckbox = doc.getElementById("submitTelemetryBox");
   Assert.ok(!telmetryCheckbox.disabled,
             "Telemetry checkbox must be enabled if FHR is checked.");
+  Assert.ok(Services.prefs.getBoolPref(PREF_TELEMETRY_ENABLED),
+            "Telemetry must be enabled if the checkbox is ticked.");
 
   // Uncheck the FHR checkbox and make sure that Telemetry checkbox gets disabled.
   fhrCheckbox.click();
 
   Assert.ok(telmetryCheckbox.disabled,
             "Telemetry checkbox must be disabled if FHR is unchecked.");
+  Assert.ok(!Services.prefs.getBoolPref(PREF_TELEMETRY_ENABLED),
+            "Telemetry must be disabled if the checkbox is unticked.");
 
   win.close();
   finish();
 }
 
 function resetPreferences() {
   Services.prefs.clearUserPref("datareporting.healthreport.uploadEnabled");
+  Services.prefs.clearUserPref(PREF_TELEMETRY_ENABLED);
 }
 
--- a/browser/components/preferences/tests/browser_telemetry.js
+++ b/browser/components/preferences/tests/browser_telemetry.js
@@ -1,13 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
+
 function runPaneTest(fn) {
   function observer(win, topic, data) {
     Services.obs.removeObserver(observer, "advanced-pane-loaded");
 
     let policy = Components.classes["@mozilla.org/datareporting/service;1"]
                                    .getService(Components.interfaces.nsISupports)
                                    .wrappedJSObject
                                    .policy;
@@ -35,27 +37,32 @@ function testTelemetryState(win) {
   let doc = win.document;
 
   let fhrCheckbox = doc.getElementById("submitHealthReportBox");
   Assert.ok(fhrCheckbox.checked, "Health Report checkbox is checked on app first run.");
 
   let telmetryCheckbox = doc.getElementById("submitTelemetryBox");
   Assert.ok(!telmetryCheckbox.disabled,
             "Telemetry checkbox must be enabled if FHR is checked.");
+  Assert.ok(Services.prefs.getBoolPref(PREF_TELEMETRY_ENABLED),
+            "Telemetry must be enabled if the checkbox is ticked.");
 
   // Uncheck the FHR checkbox and make sure that Telemetry checkbox gets disabled.
   fhrCheckbox.click();
 
   Assert.ok(telmetryCheckbox.disabled,
             "Telemetry checkbox must be disabled if FHR is unchecked.");
+  Assert.ok(!Services.prefs.getBoolPref(PREF_TELEMETRY_ENABLED),
+            "Telemetry must be disabled if the checkbox is unticked.");
 
   win.close();
   finish();
 }
 
 function resetPreferences() {
   let service = Cc["@mozilla.org/datareporting/service;1"]
                   .getService(Ci.nsISupports)
                   .wrappedJSObject;
   service.policy._prefs.resetBranch("datareporting.policy.");
   service.policy.dataSubmissionPolicyBypassNotification = true;
+  Services.prefs.clearUserPref(PREF_TELEMETRY_ENABLED);
 }
 
--- a/config/check_spidermonkey_style.py
+++ b/config/check_spidermonkey_style.py
@@ -238,41 +238,46 @@ def check_style():
     #
     # Examples (filename -> inclname)
     # - "mfbt/Attributes.h"     -> "mozilla/Attributes.h"
     # - "mfbt/decimal/Decimal.h -> "mozilla/Decimal.h"
     # - "js/public/Vector.h"    -> "js/Vector.h"
     # - "js/src/vm/String.h"    -> "vm/String.h"
 
     mfbt_inclnames = set()      # type: set(inclname)
+    mozalloc_inclnames = set()  # type: set(inclname)
     js_names = dict()           # type: dict(filename, inclname)
 
     # Select the appropriate files.
     for filename in get_all_filenames():
         if filename.startswith('mfbt/') and filename.endswith('.h'):
             inclname = 'mozilla/' + filename.split('/')[-1]
             mfbt_inclnames.add(inclname)
 
+        if filename.startswith('memory/mozalloc/') and filename.endswith('.h'):
+            inclname = 'mozilla/' + filename.split('/')[-1]
+            mozalloc_inclnames.add(inclname)
+
         if filename.startswith('js/public/') and filename.endswith('.h'):
             inclname = 'js/' + filename[len('js/public/'):]
             js_names[filename] = inclname
 
         if filename.startswith('js/src/') and \
            not filename.startswith(tuple(ignored_js_src_dirs)) and \
            filename.endswith(('.c', '.cpp', '.h', '.tbl', '.msg')):
             inclname = filename[len('js/src/'):]
             js_names[filename] = inclname
 
-    all_inclnames = mfbt_inclnames | set(js_names.values())
+    all_inclnames = mfbt_inclnames | mozalloc_inclnames | set(js_names.values())
 
     edges = dict()      # type: dict(inclname, set(inclname))
 
-    # We don't care what's inside the MFBT files, but because they are
-    # #included from JS files we have to add them to the inclusion graph.
-    for inclname in mfbt_inclnames:
+    # We don't care what's inside the MFBT and MOZALLOC files, but because they
+    # are #included from JS files we have to add them to the inclusion graph.
+    for inclname in mfbt_inclnames | mozalloc_inclnames:
         edges[inclname] = set()
 
     # Process all the JS files.
     for filename in js_names.keys():
         inclname = js_names[filename]
         file_kind = FileKind.get(filename)
         if file_kind == FileKind.C or file_kind == FileKind.CPP or \
            file_kind == FileKind.H or file_kind == FileKind.INL_H:
--- a/configure.in
+++ b/configure.in
@@ -3431,30 +3431,16 @@ dnl See if compiler supports some gcc-st
 
 AC_CACHE_CHECK(for __attribute__((always_inline)),
                ac_cv_attribute_always_inline,
                [AC_TRY_COMPILE([inline void f(void) __attribute__((always_inline));],
                                [],
                                ac_cv_attribute_always_inline=yes,
                                ac_cv_attribute_always_inline=no)])
 
-AC_CACHE_CHECK(for __attribute__((malloc)),
-               ac_cv_attribute_malloc,
-               [AC_TRY_COMPILE([void* f(int) __attribute__((malloc));],
-                               [],
-                               ac_cv_attribute_malloc=yes,
-                               ac_cv_attribute_malloc=no)])
-
-AC_CACHE_CHECK(for __attribute__((warn_unused_result)),
-               ac_cv_attribute_warn_unused,
-               [AC_TRY_COMPILE([int f(void) __attribute__((warn_unused_result));],
-                               [],
-                               ac_cv_attribute_warn_unused=yes,
-                               ac_cv_attribute_warn_unused=no)])
-
 dnl End of C++ language/feature checks
 AC_LANG_C
 
 dnl ========================================================
 dnl =  Internationalization checks
 dnl ========================================================
 dnl
 dnl Internationalization and Locale support is different
@@ -3476,45 +3462,31 @@ AC_HAVE_FUNCS(localeconv)
 fi # ! SKIP_COMPILER_CHECKS
 
 TARGET_XPCOM_ABI=
 if test -n "${CPU_ARCH}" -a -n "${TARGET_COMPILER_ABI}"; then
     TARGET_XPCOM_ABI="${CPU_ARCH}-${TARGET_COMPILER_ABI}"
     AC_DEFINE_UNQUOTED(TARGET_XPCOM_ABI, ["${TARGET_XPCOM_ABI}"])
 fi
 
-dnl Mozilla specific options
-dnl ========================================================
-dnl The macros used for command line options
-dnl are defined in build/autoconf/altoptions.m4.
-
-dnl If the compiler supports these attributes, define them as
-dnl convenience macros.
-if test "$ac_cv_attribute_malloc" = yes ; then
-  AC_DEFINE(NS_ATTR_MALLOC, [__attribute__((malloc))])
-else
-  AC_DEFINE(NS_ATTR_MALLOC,)
-fi
-
-if test "$ac_cv_attribute_warn_unused" = yes ; then
-  AC_DEFINE(NS_WARN_UNUSED_RESULT, [__attribute__((warn_unused_result))])
-else
-  AC_DEFINE(NS_WARN_UNUSED_RESULT,)
-fi
-
 dnl We can't run TRY_COMPILE tests on Windows, so hard-code some
 dnl features that Windows actually does support.
 
 if test -n "$SKIP_COMPILER_CHECKS"; then
    dnl Windows has malloc.h
    AC_DEFINE(MALLOC_H, [<malloc.h>])
    AC_DEFINE(HAVE_FORCEINLINE)
    AC_DEFINE(HAVE_LOCALECONV)
 fi # SKIP_COMPILER_CHECKS
 
+dnl Mozilla specific options
+dnl ========================================================
+dnl The macros used for command line options
+dnl are defined in build/autoconf/altoptions.m4.
+
 dnl ========================================================
 dnl =
 dnl = Check for external package dependencies
 dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(External Packages)
 
 MOZ_ARG_WITH_STRING(libxul-sdk,
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -5018,46 +5018,59 @@ nsDocShell::DisplayLoadError(nsresult aE
       if (nsserr) {
         nsserr->GetErrorMessage(aError, messageStr);
       }
     }
     if (!messageStr.IsEmpty()) {
       if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
         error.AssignLiteral("nssBadCert");
 
-        // if this is a Strict-Transport-Security host and the cert
-        // is bad, don't allow overrides (STS Spec section 7.3).
-        uint32_t type = nsISiteSecurityService::HEADER_HSTS;
+        // If this is an HTTP Strict Transport Security host or a pinned host
+        // and the certificate is bad, don't allow overrides (RFC 6797 section
+        // 12.1, HPKP draft spec section 2.6).
         uint32_t flags =
           mInPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
         bool isStsHost = false;
+        bool isPinnedHost = false;
         if (XRE_GetProcessType() == GeckoProcessType_Default) {
           nsCOMPtr<nsISiteSecurityService> sss =
             do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
           NS_ENSURE_SUCCESS(rv, rv);
-          rv = sss->IsSecureURI(type, aURI, flags, &isStsHost);
+          rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
+                                flags, &isStsHost);
+          NS_ENSURE_SUCCESS(rv, rv);
+          rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI,
+                                flags, &isPinnedHost);
           NS_ENSURE_SUCCESS(rv, rv);
         } else {
           mozilla::dom::ContentChild* cc =
             mozilla::dom::ContentChild::GetSingleton();
           mozilla::ipc::URIParams uri;
           SerializeURI(aURI, uri);
-          cc->SendIsSecureURI(type, uri, flags, &isStsHost);
+          cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags,
+                              &isStsHost);
+          cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HPKP, uri, flags,
+                              &isPinnedHost);
         }
 
         if (Preferences::GetBool(
               "browser.xul.error_pages.expert_bad_cert", false)) {
           cssClass.AssignLiteral("expertBadCert");
         }
 
-        // HSTS takes precedence over the expert bad cert pref. We
-        // never want to show the "Add Exception" button for HSTS sites.
+        // HSTS/pinning takes precedence over the expert bad cert pref. We
+        // never want to show the "Add Exception" button for these sites.
+        // In the future we should differentiate between an HSTS host and a
+        // pinned host and display a more informative message to the user.
+        if (isStsHost || isPinnedHost) {
+          cssClass.AssignLiteral("badStsCert");
+        }
+
         uint32_t bucketId;
         if (isStsHost) {
-          cssClass.AssignLiteral("badStsCert");
           // measuring STS separately allows us to measure click through
           // rates easily
           bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS;
         } else {
           bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP;
         }
 
         // See if an alternate cert error page is registered
@@ -11456,17 +11469,17 @@ nsDocShell::AddState(JS::Handle<JS::Valu
   {
     nsCOMPtr<nsIDocument> origDocument = GetDocument();
     if (!origDocument) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
     nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
 
     scContainer = new nsStructuredCloneContainer();
-    rv = scContainer->InitFromJSVal(aData);
+    rv = scContainer->InitFromJSVal(aData, aCx);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIDocument> newDocument = GetDocument();
     if (!newDocument) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
     nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
 
--- a/dom/alarm/test/mochitest.ini
+++ b/dom/alarm/test/mochitest.ini
@@ -1,11 +1,9 @@
 [DEFAULT]
-skip-if = e10s
-
 support-files =
   file_empty.html
 
 [test_alarm_add_data.html]
 skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_alarm_add_date.html]
 skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_alarm_add_respectTimezone.html]
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -451,17 +451,17 @@ nsChildContentList::IndexOf(nsIContent* 
 
 nsIHTMLCollection*
 FragmentOrElement::Children()
 {
   FragmentOrElement::nsDOMSlots *slots = DOMSlots();
 
   if (!slots->mChildrenList) {
     slots->mChildrenList = new nsContentList(this, kNameSpaceID_Wildcard, 
-                                             nsGkAtoms::_asterix, nsGkAtoms::_asterix,
+                                             nsGkAtoms::_asterisk, nsGkAtoms::_asterisk,
                                              false);
   }
 
   return slots->mChildrenList;
 }
 
 
 //----------------------------------------------------------------------
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -12,17 +12,16 @@
 #ifndef FragmentOrElement_h___
 #define FragmentOrElement_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsAttrAndChildArray.h"          // member
 #include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
 #include "nsIContent.h"                   // base class
-#include "nsINodeList.h"                  // base class
 #include "nsIWeakReference.h"             // base class
 #include "nsNodeUtils.h"                  // class member nsNodeUtils::CloneNodeImpl
 #include "nsIHTMLCollection.h"
 
 class ContentUnbinder;
 class nsContentList;
 class nsDOMAttributeMap;
 class nsDOMTokenList;
@@ -34,60 +33,16 @@ class nsIURI;
 
 namespace mozilla {
 namespace dom {
 class Element;
 }
 }
 
 /**
- * Class that implements the nsIDOMNodeList interface (a list of children of
- * the content), by holding a reference to the content and delegating GetLength
- * and Item to its existing child list.
- * @see nsIDOMNodeList
- */
-class nsChildContentList final : public nsINodeList
-{
-public:
-  explicit nsChildContentList(nsINode* aNode)
-    : mNode(aNode)
-  {
-  }
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsChildContentList)
-
-  // nsWrapperCache
-  virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
-
-  // nsIDOMNodeList interface
-  NS_DECL_NSIDOMNODELIST
-
-  // nsINodeList interface
-  virtual int32_t IndexOf(nsIContent* aContent) override;
-  virtual nsIContent* Item(uint32_t aIndex) override;
-
-  void DropReference()
-  {
-    mNode = nullptr;
-  }
-
-  virtual nsINode* GetParentObject() override
-  {
-    return mNode;
-  }
-
-private:
-  ~nsChildContentList() {}
-
-  // The node whose children make up the list (weak reference)
-  nsINode* mNode;
-};
-
-/**
  * A class that implements nsIWeakReference
  */
 
 class nsNodeWeakReference final : public nsIWeakReference
 {
 public:
   explicit nsNodeWeakReference(nsINode* aNode)
     : mNode(aNode)
@@ -181,18 +136,18 @@ public:
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const char16_t* aBuffer, uint32_t aLength,
                               bool aNotify) override;
   virtual bool TextIsOnlyWhitespace() override;
   virtual bool HasTextForTranslation() override;
   virtual void AppendTextTo(nsAString& aResult) override;
-  virtual bool AppendTextTo(nsAString& aResult,
-                            const mozilla::fallible_t&) override NS_WARN_UNUSED_RESULT; 
+  MOZ_WARN_UNUSED_RESULT
+  virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) override;
   virtual nsIContent *GetBindingParent() const override;
   virtual nsXBLBinding *GetXBLBinding() const override;
   virtual void SetXBLBinding(nsXBLBinding* aBinding,
                              nsBindingManager* aOldBindingManager = nullptr) override;
   virtual ShadowRoot *GetShadowRoot() const override;
   virtual ShadowRoot *GetContainingShadow() const override;
   virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
   virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/1154598.xhtml
@@ -0,0 +1,9 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body><body>
+<script>
+s = document.createElement('script');
+s.src="";
+document.body.appendChild(s);
+</script>
+</body>
+</html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -195,8 +195,10 @@ load 973401.html
 load 978646.html
 pref(dom.webcomponents.enabled,true) load 1027461-1.html
 pref(dom.webcomponents.enabled,true) load 1024428-1.html
 load 1026714.html
 pref(dom.webcomponents.enabled,true) load 1029710.html
 HTTP(..) load xhr_abortinprogress.html
 load xhr_empty_datauri.html
 load xhr_html_nullresponse.html
+load structured_clone_container_throws.html
+load 1154598.xhtml
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/structured_clone_container_throws.html
@@ -0,0 +1,9 @@
+<iframe></iframe>
+<script>
+try { frames[0].history.pushState({ dummy: function() {} }, ''); }
+catch (e) {}
+var doc = frames[0].document;
+var s = doc.createElement("script");
+s.textContent = "1";
+doc.body.appendChild(s);
+</script>
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -412,16 +412,17 @@ LOCAL_INCLUDES += [
     '/dom/ipc',
     '/dom/storage',
     '/dom/svg',
     '/dom/workers',
     '/dom/xbl',
     '/dom/xml',
     '/dom/xslt/xpath',
     '/dom/xul',
+    '/gfx/2d',
     '/image/src',
     '/js/xpconnect/src',
     '/js/xpconnect/wrappers',
     '/layout/base',
     '/layout/generic',
     '/layout/style',
     '/layout/svg',
     '/layout/xul',
--- a/dom/base/nsContentList.cpp
+++ b/dom/base/nsContentList.cpp
@@ -399,18 +399,18 @@ nsContentList::nsContentList(nsINode* aR
     mFunc(nullptr),
     mDestroyFunc(nullptr),
     mData(nullptr),
     mState(LIST_DIRTY),
     mDeep(aDeep),
     mFuncMayDependOnAttr(false)
 {
   NS_ASSERTION(mRootNode, "Must have root");
-  if (nsGkAtoms::_asterix == mHTMLMatchAtom) {
-    NS_ASSERTION(mXMLMatchAtom == nsGkAtoms::_asterix, "HTML atom and XML atom are not both asterix?");
+  if (nsGkAtoms::_asterisk == mHTMLMatchAtom) {
+    NS_ASSERTION(mXMLMatchAtom == nsGkAtoms::_asterisk, "HTML atom and XML atom are not both asterisk?");
     mMatchAll = true;
   }
   else {
     mMatchAll = false;
   }
   mRootNode->AddMutationObserver(this);
 
   // We only need to flush if we're in an non-HTML document, since the
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -166,16 +166,17 @@
 #include "nsParserCIID.h"
 #include "nsParserConstants.h"
 #include "nsPIDOMWindow.h"
 #include "nsPresContext.h"
 #include "nsPrintfCString.h"
 #include "nsReferencedElement.h"
 #include "nsSandboxFlags.h"
 #include "nsScriptSecurityManager.h"
+#include "nsStreamUtils.h"
 #include "nsSVGFeatures.h"
 #include "nsTextEditorState.h"
 #include "nsTextFragment.h"
 #include "nsTextNode.h"
 #include "nsThreadUtils.h"
 #include "nsUnicharUtilCIID.h"
 #include "nsUnicodeProperties.h"
 #include "nsViewManager.h"
@@ -7214,92 +7215,179 @@ nsContentUtils::CallOnAllRemoteChildren(
 
 void
 nsContentUtils::TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
                                                 nsTArray<IPCDataTransfer>& aIPC,
                                                 mozilla::dom::nsIContentChild* aChild,
                                                 mozilla::dom::nsIContentParent* aParent)
 {
   aIPC.Clear();
-  MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent));
   if (aTransferables) {
     uint32_t transferableCount = 0;
     aTransferables->Count(&transferableCount);
     for (uint32_t i = 0; i < transferableCount; ++i) {
       IPCDataTransfer* dt = aIPC.AppendElement();
       nsCOMPtr<nsISupports> genericItem;
       aTransferables->GetElementAt(i, getter_AddRefs(genericItem));
-      nsCOMPtr<nsITransferable> item(do_QueryInterface(genericItem));
-      if (item) {
-        nsCOMPtr<nsISupportsArray> flavorList;
-        item->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
-        if (flavorList) {
-          uint32_t flavorCount = 0;
-          flavorList->Count(&flavorCount);
-          for (uint32_t j = 0; j < flavorCount; ++j) {
-            nsCOMPtr<nsISupportsCString> flavor = do_QueryElementAt(flavorList, j);
-            if (!flavor) {
-              continue;
+      nsCOMPtr<nsITransferable> transferable(do_QueryInterface(genericItem));
+      TransferableToIPCTransferable(transferable, dt, aChild, aParent);
+    }
+  }
+}
+
+void
+nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
+                                              IPCDataTransfer* aIPCDataTransfer,
+                                              mozilla::dom::nsIContentChild* aChild,
+                                              mozilla::dom::nsIContentParent* aParent)
+{
+  MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent));
+
+  if (aTransferable) {
+    nsCOMPtr<nsISupportsArray> flavorList;
+    aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
+    if (flavorList) {
+      uint32_t flavorCount = 0;
+      flavorList->Count(&flavorCount);
+      for (uint32_t j = 0; j < flavorCount; ++j) {
+        nsCOMPtr<nsISupportsCString> flavor = do_QueryElementAt(flavorList, j);
+        if (!flavor) {
+          continue;
+        }
+
+        nsAutoCString flavorStr;
+        flavor->GetData(flavorStr);
+        if (!flavorStr.Length()) {
+          continue;
+        }
+
+        nsCOMPtr<nsISupports> data;
+        uint32_t dataLen = 0;
+        aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(data), &dataLen);
+
+        nsCOMPtr<nsISupportsString> text = do_QueryInterface(data);
+        nsCOMPtr<nsISupportsCString> ctext = do_QueryInterface(data);
+        if (text) {
+          nsAutoString dataAsString;
+          text->GetData(dataAsString);
+          IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+          item->flavor() = nsCString(flavorStr);
+          item->data() = nsString(dataAsString);
+        } else if (ctext) {
+          nsAutoCString dataAsString;
+          ctext->GetData(dataAsString);
+          IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+          item->flavor() = nsCString(flavorStr);
+          item->data() = nsCString(dataAsString);
+        } else {
+          nsCOMPtr<nsISupportsInterfacePointer> sip =
+            do_QueryInterface(data);
+          if (sip) {
+            sip->GetData(getter_AddRefs(data));
+          }
+
+          // Images to be pasted on the clipboard are nsIInputStreams
+          nsCOMPtr<nsIInputStream> stream(do_QueryInterface(data));
+          if (stream) {
+            IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+            item->flavor() = nsCString(flavorStr);
+
+            nsCString imageData;
+            NS_ConsumeStream(stream, UINT32_MAX, imageData);
+            item->data() = imageData;
+            continue;
+          }
+
+          // Images to be placed on the clipboard are imgIContainers.
+          nsCOMPtr<imgIContainer> image(do_QueryInterface(data));
+          if (image) {
+            RefPtr<mozilla::gfx::SourceSurface> surface =
+              image->GetFrame(imgIContainer::FRAME_CURRENT,
+                              imgIContainer::FLAG_SYNC_DECODE);
+
+            mozilla::RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
+              surface->GetDataSurface();
+            size_t length;
+            int32_t stride;
+            mozilla::UniquePtr<char[]> surfaceData =
+              nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
+            
+            IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+            item->flavor() = nsCString(flavorStr);
+            item->data() = nsCString(surfaceData.get(), length);
+
+            IPCDataTransferImage& imageDetails = item->imageDetails();
+            mozilla::gfx::IntSize size = dataSurface->GetSize();
+            imageDetails.width() = size.width;
+            imageDetails.height() = size.height;
+            imageDetails.stride() = stride;
+            imageDetails.format() = static_cast<uint8_t>(dataSurface->GetFormat());
+
+            continue;
+          }
+
+          // Otherwise, handle this as a file.
+          nsCOMPtr<FileImpl> fileImpl;
+          nsCOMPtr<nsIFile> file = do_QueryInterface(data);
+          if (file) {
+            fileImpl = new FileImplFile(file, false);
+            ErrorResult rv;
+            fileImpl->GetSize(rv);
+            fileImpl->GetLastModified(rv);
+          } else {
+            fileImpl = do_QueryInterface(data);
+          }
+          if (fileImpl) {
+            IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+            item->flavor() = nsCString(flavorStr);
+            if (aChild) {
+              item->data() =
+                mozilla::dom::BlobChild::GetOrCreate(aChild,
+                  static_cast<FileImpl*>(fileImpl.get()));
+            } else if (aParent) {
+              item->data() =
+                mozilla::dom::BlobParent::GetOrCreate(aParent,
+                  static_cast<FileImpl*>(fileImpl.get()));
             }
-
-            nsAutoCString flavorStr;
-            flavor->GetData(flavorStr);
-            if (!flavorStr.Length()) {
-              continue;
-            }
-
-            nsCOMPtr<nsISupports> data;
-            uint32_t dataLen = 0;
-            item->GetTransferData(flavorStr.get(), getter_AddRefs(data), &dataLen);
-
-            nsCOMPtr<nsISupportsString> text = do_QueryInterface(data);
-            if (text) {
-              nsAutoString dataAsString;
-              text->GetData(dataAsString);
-              IPCDataTransferItem* item = dt->items().AppendElement();
+          } else {
+            // This is a hack to support kFilePromiseMime.
+            // On Windows there just needs to be an entry for it, 
+            // and for OSX we need to create
+            // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
+            if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
+              IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
               item->flavor() = nsCString(flavorStr);
-              item->data() = nsString(dataAsString);
-            } else {
-              nsCOMPtr<nsISupportsInterfacePointer> sip =
-                do_QueryInterface(data);
-              if (sip) {
-                sip->GetData(getter_AddRefs(data));
-              }
-              nsCOMPtr<FileImpl> fileImpl;
-              nsCOMPtr<nsIFile> file = do_QueryInterface(data);
-              if (file) {
-                fileImpl = new FileImplFile(file, false);
-                ErrorResult rv;
-                fileImpl->GetSize(rv);
-                fileImpl->GetLastModified(rv);
-              } else {
-                fileImpl = do_QueryInterface(data);
-              }
-              if (fileImpl) {
-                IPCDataTransferItem* item = dt->items().AppendElement();
-                item->flavor() = nsCString(flavorStr);
-                if (aChild) {
-                  item->data() =
-                    mozilla::dom::BlobChild::GetOrCreate(aChild,
-                      static_cast<FileImpl*>(fileImpl.get()));
-                } else if (aParent) {
-                  item->data() =
-                    mozilla::dom::BlobParent::GetOrCreate(aParent,
-                      static_cast<FileImpl*>(fileImpl.get()));
-                }
-              } else {
-                // This is a hack to support kFilePromiseMime.
-                // On Windows there just needs to be an entry for it, 
-                // and for OSX we need to create
-                // nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
-                if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
-                  IPCDataTransferItem* item = dt->items().AppendElement();
-                  item->flavor() = nsCString(flavorStr);
-                  item->data() = NS_ConvertUTF8toUTF16(flavorStr);
-                }
-              }
+              item->data() = NS_ConvertUTF8toUTF16(flavorStr);
             }
           }
         }
       }
     }
   }
 }
+
+mozilla::UniquePtr<char[]>
+nsContentUtils::GetSurfaceData(mozilla::gfx::DataSourceSurface* aSurface,
+                               size_t* aLength, int32_t* aStride)
+{
+  mozilla::gfx::DataSourceSurface::MappedSurface map;
+  aSurface->Map(mozilla::gfx::DataSourceSurface::MapType::READ, &map);
+  mozilla::gfx::IntSize size = aSurface->GetSize();
+  mozilla::CheckedInt32 requiredBytes =
+    mozilla::CheckedInt32(map.mStride) * mozilla::CheckedInt32(size.height);
+  size_t maxBufLen = requiredBytes.isValid() ? requiredBytes.value() : 0;
+  mozilla::gfx::SurfaceFormat format = aSurface->GetFormat();
+
+  // Surface data handling is totally nuts. This is the magic one needs to
+  // know to access the data.
+  size_t bufLen = maxBufLen - map.mStride + (size.width * BytesPerPixel(format));
+
+  // nsDependentCString wants null-terminated string.
+  mozilla::UniquePtr<char[]> surfaceData(new char[maxBufLen + 1]);
+  memcpy(surfaceData.get(), reinterpret_cast<char*>(map.mData), bufLen);
+  memset(surfaceData.get() + bufLen, 0, maxBufLen - bufLen + 1);
+
+  *aLength = maxBufLen;
+  *aStride = map.mStride;
+
+  aSurface->Unmap();
+  return surfaceData;
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -98,16 +98,17 @@ class nsPIDOMWindow;
 class nsPresContext;
 class nsScriptObjectTracer;
 class nsStringBuffer;
 class nsStringHashKey;
 class nsTextFragment;
 class nsViewportInfo;
 class nsWrapperCache;
 class nsAttrValue;
+class nsITransferable;
 
 struct JSPropertyDescriptor;
 struct JSRuntime;
 struct nsIntMargin;
 
 template<class E> class nsCOMArray;
 template<class K, class V> class nsDataHashtable;
 template<class K, class V> class nsRefPtrHashtable;
@@ -124,16 +125,20 @@ class EventTarget;
 class IPCDataTransfer;
 class NodeInfo;
 class nsIContentChild;
 class nsIContentParent;
 class Selection;
 class TabParent;
 } // namespace dom
 
+namespace gfx {
+class DataSourceSurface;
+} // namespace gfx
+
 namespace layers {
 class LayerManager;
 } // namespace layers
 
 } // namespace mozilla
 
 class nsIBidiKeyboard;
 
@@ -1272,18 +1277,19 @@ public:
    * added to the result.
    *
    * @param aNode Node to get textual contents of.
    * @param aDeep If true child elements of aNode are recursivly descended
    *              into to find text children.
    * @param aResult the result. Out param.
    * @return false on out of memory errors, true otherwise.
    */
+  MOZ_WARN_UNUSED_RESULT
   static bool GetNodeTextContent(nsINode* aNode, bool aDeep,
-                                 nsAString& aResult) NS_WARN_UNUSED_RESULT;
+                                 nsAString& aResult);
 
   /**
    * Same as GetNodeTextContents but appends the result rather than sets it.
    */
   static bool AppendNodeTextContent(nsINode* aNode, bool aDeep,
                                     nsAString& aResult, const mozilla::fallible_t&);
 
   /**
@@ -1748,18 +1754,19 @@ public:
    */
   static void RemoveNewlines(nsString &aString);
 
   /**
    * Convert Windows and Mac platform linebreaks to \n.
    * @param aString the string to convert the newlines inside [in/out]
    */
   static void PlatformToDOMLineBreaks(nsString &aString);
-  static NS_WARN_UNUSED_RESULT bool PlatformToDOMLineBreaks(nsString &aString,
-                                                            const mozilla::fallible_t&);
+  MOZ_WARN_UNUSED_RESULT
+  static bool PlatformToDOMLineBreaks(nsString &aString,
+                                      const mozilla::fallible_t&);
 
   /**
    * Populates aResultString with the contents of the string-buffer aBuf, up
    * to aBuf's null-terminator.  aBuf must not be null. Ownership of the string
    * is not transferred.
    */
   static void PopulateStringFromStringBuffer(nsStringBuffer* aBuf,
                                              nsAString& aResultString);
@@ -2291,16 +2298,29 @@ public:
   static void CallOnAllRemoteChildren(nsIDOMWindow* aWindow,
                                       CallOnRemoteChildFunction aCallback,
                                       void* aArg);
 
   static void TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
                                               nsTArray<mozilla::dom::IPCDataTransfer>& aIPC,
                                               mozilla::dom::nsIContentChild* aChild,
                                               mozilla::dom::nsIContentParent* aParent);
+
+  static void TransferableToIPCTransferable(nsITransferable* aTransferable,
+                                            mozilla::dom::IPCDataTransfer* aIPCDataTransfer,
+                                            mozilla::dom::nsIContentChild* aChild,
+                                            mozilla::dom::nsIContentParent* aParent);
+
+  /*
+   * Get the pixel data from the given source surface and return it as a buffer.
+   * The length and stride will be assigned from the surface.
+   */
+  static mozilla::UniquePtr<char[]> GetSurfaceData(mozilla::gfx::DataSourceSurface* aSurface,
+                                                   size_t* aLength, int32_t* aStride);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/base/nsDOMAttributeMap.h
+++ b/dom/base/nsDOMAttributeMap.h
@@ -29,20 +29,20 @@ class nsAttrKey
 {
 public:
   /**
    * The namespace of the attribute
    */
   int32_t  mNamespaceID;
 
   /**
-   * The atom for attribute, weak ref. is fine as we only use it for the
-   * hashcode, we never dereference it.
+   * The atom for attribute, stored as void*, to make sure that we only use it
+   * for the hashcode, and we can never dereference it.
    */
-  nsIAtom* mLocalName;
+  void* mLocalName;
 
   nsAttrKey(int32_t aNs, nsIAtom* aName)
     : mNamespaceID(aNs), mLocalName(aName) {}
 
   nsAttrKey(const nsAttrKey& aAttr)
     : mNamespaceID(aAttr.mNamespaceID), mLocalName(aAttr.mLocalName) {}
 };
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -10826,18 +10826,18 @@ nsIDocument::ObsoleteSheet(const nsAStri
   }
 }
 
 nsIHTMLCollection*
 nsIDocument::Children()
 {
   if (!mChildrenCollection) {
     mChildrenCollection = new nsContentList(this, kNameSpaceID_Wildcard,
-                                            nsGkAtoms::_asterix,
-                                            nsGkAtoms::_asterix,
+                                            nsGkAtoms::_asterisk,
+                                            nsGkAtoms::_asterisk,
                                             false);
   }
 
   return mChildrenCollection;
 }
 
 uint32_t
 nsIDocument::ChildElementCount()
--- a/dom/base/nsGenericDOMDataNode.h
+++ b/dom/base/nsGenericDOMDataNode.h
@@ -137,18 +137,19 @@ public:
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const char16_t* aBuffer, uint32_t aLength,
                               bool aNotify) override;
   virtual bool TextIsOnlyWhitespace() override;
   virtual bool HasTextForTranslation() override;
   virtual void AppendTextTo(nsAString& aResult) override;
+  MOZ_WARN_UNUSED_RESULT
   virtual bool AppendTextTo(nsAString& aResult,
-                            const mozilla::fallible_t&) override NS_WARN_UNUSED_RESULT;
+                            const mozilla::fallible_t&) override;
   virtual void DestroyContent() override;
   virtual void SaveSubtreeState() override;
 
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const override;
   virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override;
 #endif
 
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -45,17 +45,17 @@ GK_ATOM(mozgeneratedcontentafter, "_moz_
 GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image")
 GK_ATOM(mozquote, "_moz_quote")
 GK_ATOM(mozsignature, "moz-signature")
 GK_ATOM(_moz_is_glyph, "-moz-is-glyph")
 GK_ATOM(_moz_original_size, "_moz_original_size")
 GK_ATOM(_moz_target, "_moz_target")
 GK_ATOM(menuactive, "_moz-menuactive")
 GK_ATOM(_poundDefault, "#default")
-GK_ATOM(_asterix, "*")
+GK_ATOM(_asterisk, "*")
 GK_ATOM(a, "a")
 GK_ATOM(abbr, "abbr")
 GK_ATOM(abort, "abort")
 GK_ATOM(above, "above")
 GK_ATOM(acceltext, "acceltext")
 GK_ATOM(accept, "accept")
 GK_ATOM(acceptcharset, "accept-charset")
 GK_ATOM(accesskey, "accesskey")
--- a/dom/base/nsHTMLContentSerializer.h
+++ b/dom/base/nsHTMLContentSerializer.h
@@ -31,26 +31,26 @@ class nsHTMLContentSerializer final : pu
 
   NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
                               nsAString& aStr) override;
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr) override;
  protected:
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool SerializeHTMLAttributes(nsIContent* aContent,
                                        nsIContent *aOriginalElement,
                                        nsAString& aTagPrefix,
                                        const nsAString& aTagNamespaceURI,
                                        nsIAtom* aTagName,
                                        int32_t aNamespace,
                                        nsAString& aStr);
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool AppendAndTranslateEntities(const nsAString& aStr,
                                           nsAString& aOutputStr) override;
 
 };
 
 nsresult
 NS_NewHTMLContentSerializer(nsIContentSerializer** aSerializer);
 
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -540,18 +540,18 @@ public:
    * NOTE: This asserts and returns for elements
    */
   virtual void AppendTextTo(nsAString& aResult) = 0;
 
   /**
    * Append the text content to aResult.
    * NOTE: This asserts and returns for elements
    */
-  virtual bool AppendTextTo(nsAString& aResult,
-                            const mozilla::fallible_t&) NS_WARN_UNUSED_RESULT = 0;
+  MOZ_WARN_UNUSED_RESULT
+  virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) = 0;
 
   /**
    * Check if this content is focusable and in the current tab order.
    * Note: most callers should use nsIFrame::IsFocusable() instead as it 
    *       checks visibility and other layout factors as well.
    * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
    * For example, only the selected radio button in a group is in the 
    * tab order, unless the radio group has no selection in which case
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -108,17 +108,16 @@
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsINode::nsSlots::~nsSlots()
 {
   if (mChildNodes) {
     mChildNodes->DropReference();
-    NS_RELEASE(mChildNodes);
   }
 
   if (mWeakReference) {
     mWeakReference->NoticeNodeDestruction();
   }
 }
 
 void
@@ -128,17 +127,16 @@ nsINode::nsSlots::Traverse(nsCycleCollec
   cb.NoteXPCOMChild(mChildNodes);
 }
 
 void
 nsINode::nsSlots::Unlink()
 {
   if (mChildNodes) {
     mChildNodes->DropReference();
-    NS_RELEASE(mChildNodes);
   }
 }
 
 //----------------------------------------------------------------------
 
 nsINode::~nsINode()
 {
   MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
@@ -366,19 +364,16 @@ nsINode::GetSelectionRootContent(nsIPres
 }
 
 nsINodeList*
 nsINode::ChildNodes()
 {
   nsSlots* slots = Slots();
   if (!slots->mChildNodes) {
     slots->mChildNodes = new nsChildContentList(this);
-    if (slots->mChildNodes) {
-      NS_ADDREF(slots->mChildNodes);
-    }
   }
 
   return slots->mChildNodes;
 }
 
 void
 nsINode::GetTextContentInternal(nsAString& aTextContent, ErrorResult& aError)
 {
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -6,16 +6,17 @@
 #ifndef nsINode_h___
 #define nsINode_h___
 
 #include "mozilla/Likely.h"
 #include "nsCOMPtr.h"               // for member, local
 #include "nsGkAtoms.h"              // for nsGkAtoms::baseURIProperty
 #include "nsIDOMNode.h"
 #include "mozilla/dom/NodeInfo.h"            // member (in nsCOMPtr)
+#include "nsINodeList.h"            // base class
 #include "nsIVariant.h"             // for use in GetUserData()
 #include "nsNodeInfoManager.h"      // for use in NodePrincipal()
 #include "nsPropertyTable.h"        // for typedefs
 #include "nsTObserverArray.h"       // for member
 #include "mozilla/ErrorResult.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/EventTarget.h" // for base class
 #include "js/TypeDecls.h"     // for Handle, Value, JSObject, JSContext
@@ -36,17 +37,17 @@ class nsDOMAttributeMap;
 class nsIAnimationObserver;
 class nsIContent;
 class nsIDocument;
 class nsIDOMElement;
 class nsIDOMNodeList;
 class nsIEditor;
 class nsIFrame;
 class nsIMutationObserver;
-class nsINodeList;
+class nsINode;
 class nsIPresShell;
 class nsIPrincipal;
 class nsIURI;
 class nsNodeSupportsWeakRefTearoff;
 class nsNodeWeakReference;
 class nsXPCClassInfo;
 class nsDOMMutationObserver;
 
@@ -229,16 +230,60 @@ public:
 private:
   // This is the value sGeneration had when the guard was constructed.
   uint64_t mStartingGeneration;
 
   // This value is incremented on every mutation, for the life of the process.
   static uint64_t sGeneration;
 };
 
+/**
+ * Class that implements the nsIDOMNodeList interface (a list of children of
+ * the content), by holding a reference to the content and delegating GetLength
+ * and Item to its existing child list.
+ * @see nsIDOMNodeList
+ */
+class nsChildContentList final : public nsINodeList
+{
+public:
+  explicit nsChildContentList(nsINode* aNode)
+    : mNode(aNode)
+  {
+  }
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsChildContentList)
+
+  // nsWrapperCache
+  virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
+
+  // nsIDOMNodeList interface
+  NS_DECL_NSIDOMNODELIST
+
+  // nsINodeList interface
+  virtual int32_t IndexOf(nsIContent* aContent) override;
+  virtual nsIContent* Item(uint32_t aIndex) override;
+
+  void DropReference()
+  {
+    mNode = nullptr;
+  }
+
+  virtual nsINode* GetParentObject() override
+  {
+    return mNode;
+  }
+
+private:
+  ~nsChildContentList() {}
+
+  // The node whose children make up the list (weak reference)
+  nsINode* mNode;
+};
+
 // This should be used for any nsINode sub-class that has fields of its own
 // that it needs to measure;  any sub-class that doesn't use it will inherit
 // SizeOfExcludingThis from its super-class.  SizeOfIncludingThis() need not be
 // defined, it is inherited from nsINode.
 // This macro isn't actually specific to nodes, and bug 956400 will move it into MFBT.
 #define NS_DECL_SIZEOF_EXCLUDING_THIS \
   virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
@@ -1016,18 +1061,17 @@ public:
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const = 0;
 
   // This class can be extended by subclasses that wish to store more
   // information in the slots.
   class nsSlots
   {
   public:
     nsSlots()
-      : mChildNodes(nullptr),
-        mWeakReference(nullptr)
+      : mWeakReference(nullptr)
     {
     }
 
     // If needed we could remove the vtable pointer this dtor causes by
     // putting a DestroySlots function on nsINode
     virtual ~nsSlots();
 
     void Traverse(nsCycleCollectionTraversalCallback &cb);
@@ -1037,25 +1081,24 @@ public:
      * A list of mutation observers
      */
     nsTObserverArray<nsIMutationObserver*> mMutationObservers;
 
     /**
      * An object implementing nsIDOMNodeList for this content (childNodes)
      * @see nsIDOMNodeList
      * @see nsGenericHTMLElement::GetChildNodes
-     *
-     * MSVC 7 doesn't like this as an nsRefPtr
      */
-    nsChildContentList* mChildNodes;
+    nsRefPtr<nsChildContentList> mChildNodes;
 
     /**
-     * Weak reference to this node
+     * Weak reference to this node.  This is cleared by the destructor of
+     * nsNodeWeakReference.
      */
-    nsNodeWeakReference* mWeakReference;
+    nsNodeWeakReference* MOZ_NON_OWNING_REF mWeakReference;
   };
 
   /**
    * Functions for managing flags and slots
    */
 #ifdef DEBUG
   nsSlots* DebugGetSlots()
   {
--- a/dom/base/nsINodeList.h
+++ b/dom/base/nsINodeList.h
@@ -3,23 +3,25 @@
  * 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/. */
 
 #ifndef nsINodeList_h___
 #define nsINodeList_h___
 
 #include "nsIDOMNodeList.h"
 #include "nsWrapperCache.h"
-#include "nsIContent.h"
 
 // IID for the nsINodeList interface
 #define NS_INODELIST_IID \
 { 0xadb5e54c, 0x6e96, 0x4102, \
  { 0x8d, 0x40, 0xe0, 0x12, 0x3d, 0xcf, 0x48, 0x7a } }
 
+class nsIContent;
+class nsINode;
+
 /**
  * An internal interface for a reasonably fast indexOf.
  */
 class nsINodeList : public nsIDOMNodeList,
                     public nsWrapperCache
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODELIST_IID)
--- a/dom/base/nsNodeInfoManager.h
+++ b/dom/base/nsNodeInfoManager.h
@@ -124,19 +124,19 @@ protected:
 
 private:
   static int NodeInfoInnerKeyCompare(const void *key1, const void *key2);
   static PLHashNumber GetNodeInfoInnerHashValue(const void *key);
   static int DropNodeInfoDocument(PLHashEntry *he, int hashIndex,
                                      void *arg);
 
   PLHashTable *mNodeInfoHash;
-  nsIDocument *mDocument; // WEAK
+  nsIDocument * MOZ_NON_OWNING_REF mDocument; // WEAK
   uint32_t mNonDocumentNodeInfos;
   nsCOMPtr<nsIPrincipal> mPrincipal; // Never null after Init() succeeds.
   nsCOMPtr<nsIPrincipal> mDefaultPrincipal; // Never null after Init() succeeds
-  mozilla::dom::NodeInfo *mTextNodeInfo; // WEAK to avoid circular ownership
-  mozilla::dom::NodeInfo *mCommentNodeInfo; // WEAK to avoid circular ownership
-  mozilla::dom::NodeInfo *mDocumentNodeInfo; // WEAK to avoid circular ownership
+  mozilla::dom::NodeInfo * MOZ_NON_OWNING_REF mTextNodeInfo; // WEAK to avoid circular ownership
+  mozilla::dom::NodeInfo * MOZ_NON_OWNING_REF mCommentNodeInfo; // WEAK to avoid circular ownership
+  mozilla::dom::NodeInfo * MOZ_NON_OWNING_REF mDocumentNodeInfo; // WEAK to avoid circular ownership
   nsRefPtr<nsBindingManager> mBindingManager;
 };
 
 #endif /* nsNodeInfoManager_h___ */
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -71,16 +71,17 @@ nsScriptLoadRequestList::~nsScriptLoadRe
   Clear();
 }
 
 void
 nsScriptLoadRequestList::Clear()
 {
   while (!isEmpty()) {
     nsRefPtr<nsScriptLoadRequest> first = StealFirst();
+    first->Cancel();
     // And just let it go out of scope and die.
   }
 }
 
 #ifdef DEBUG
 bool
 nsScriptLoadRequestList::Contains(nsScriptLoadRequest* aElem)
 {
@@ -1481,16 +1482,20 @@ nsScriptLoader::PrepareLoadedRequest(nsS
                                      nsresult aStatus,
                                      uint32_t aStringLen,
                                      const uint8_t* aString)
 {
   if (NS_FAILED(aStatus)) {
     return aStatus;
   }
 
+  if (aRequest->IsCanceled()) {
+    return NS_BINDING_ABORTED;
+  }
+
   // If we don't have a document, then we need to abort further
   // evaluation.
   if (!mDocument) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // If the load returned an error page, then we need to abort
   nsCOMPtr<nsIRequest> req;
@@ -1551,20 +1556,25 @@ nsScriptLoader::PrepareLoadedRequest(nsS
                mXSLTRequests.Contains(aRequest)  ||
                mPreloads.Contains(aRequest, PreloadRequestComparator()) ||
                mParserBlockingRequest,
                "aRequest should be pending!");
 
   // Mark this as loaded
   aRequest->mLoading = false;
 
-  // And if it's async, move it to the loaded list.
+  // And if it's async, move it to the loaded list.  aRequest->mIsAsync really
+  // _should_ be in a list, but the consequences if it's not are bad enough we
+  // want to avoid trying to move it if it's not.
   if (aRequest->mIsAsync) {
-    nsRefPtr<nsScriptLoadRequest> req = mLoadingAsyncRequests.Steal(aRequest);
-    mLoadedAsyncRequests.AppendElement(req);
+    MOZ_ASSERT(aRequest->isInList());
+    if (aRequest->isInList()) {
+      nsRefPtr<nsScriptLoadRequest> req = mLoadingAsyncRequests.Steal(aRequest);
+      mLoadedAsyncRequests.AppendElement(req);
+    }
   }
 
   return NS_OK;
 }
 
 void
 nsScriptLoader::ParsingComplete(bool aTerminated)
 {
@@ -1575,17 +1585,20 @@ nsScriptLoader::ParsingComplete(bool aTe
   }
   mDeferEnabled = false;
   if (aTerminated) {
     mDeferRequests.Clear();
     mLoadingAsyncRequests.Clear();
     mLoadedAsyncRequests.Clear();
     mNonAsyncExternalScriptInsertedRequests.Clear();
     mXSLTRequests.Clear();
-    mParserBlockingRequest = nullptr;
+    if (mParserBlockingRequest) {
+      mParserBlockingRequest->Cancel();
+      mParserBlockingRequest = nullptr;
+    }
   }
 
   // Have to call this even if aTerminated so we'll correctly unblock
   // onload and all.
   ProcessPendingRequests();
 }
 
 void
--- a/dom/base/nsScriptLoader.h
+++ b/dom/base/nsScriptLoader.h
@@ -59,16 +59,17 @@ public:
     : mElement(aElement),
       mLoading(true),
       mIsInline(true),
       mHasSourceMapURL(false),
       mIsDefer(false),
       mIsAsync(false),
       mIsNonAsyncScriptInserted(false),
       mIsXSLT(false),
+      mIsCanceled(false),
       mScriptTextBuf(nullptr),
       mScriptTextLength(0),
       mJSVersion(aVersion),
       mLineNo(1),
       mCORSMode(aCORSMode),
       mReferrerPolicy(mozilla::net::RP_Default)
   {
   }
@@ -84,27 +85,38 @@ public:
     mElement->ScriptEvaluated(aResult, mElement, mIsInline);
   }
 
   bool IsPreload()
   {
     return mElement == nullptr;
   }
 
+  void Cancel()
+  {
+    mIsCanceled = true;
+  }
+
+  bool IsCanceled() const
+  {
+    return mIsCanceled;
+  }
+
   using super::getNext;
   using super::isInList;
 
   nsCOMPtr<nsIScriptElement> mElement;
   bool mLoading;          // Are we still waiting for a load to complete?
   bool mIsInline;         // Is the script inline or loaded?
   bool mHasSourceMapURL;  // Does the HTTP header have a source map url?
   bool mIsDefer;          // True if we live in mDeferRequests.
   bool mIsAsync;          // True if we live in mLoadingAsyncRequests or mLoadedAsyncRequests.
   bool mIsNonAsyncScriptInserted; // True if we live in mNonAsyncExternalScriptInsertedRequests
   bool mIsXSLT;           // True if we live in mXSLTRequests.
+  bool mIsCanceled;       // True if we have been explicitly canceled.
   nsString mSourceMapURL; // Holds source map url for loaded scripts
   char16_t* mScriptTextBuf; // Holds script text for non-inline scripts. Don't
   size_t mScriptTextLength; // use nsString so we can give ownership to jsapi.
   uint32_t mJSVersion;
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIPrincipal> mOriginPrincipal;
   nsAutoCString mURL;   // Keep the URI's filename alive during off thread parsing.
   int32_t mLineNo;
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -37,38 +37,29 @@ nsStructuredCloneContainer::nsStructured
 }
 
 nsStructuredCloneContainer::~nsStructuredCloneContainer()
 {
   free(mData);
 }
 
 nsresult
-nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData)
+nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData,
+                                          JSContext* aCx)
 {
   NS_ENSURE_STATE(!mData);
 
   uint64_t* jsBytes = nullptr;
   bool success = false;
   if (aData.isPrimitive()) {
-    // |aData| is a primitive, so the structured clone algorithm won't run
-    // script and we can just use AutoJSAPI.
-    dom::AutoJSAPI jsapi;
-    jsapi.Init();
-    success = JS_WriteStructuredClone(jsapi.cx(), aData, &jsBytes, &mSize,
+    success = JS_WriteStructuredClone(aCx, aData, &jsBytes, &mSize,
                                       nullptr, nullptr,
                                       JS::UndefinedHandleValue);
   } else {
-    // |aData| is an object and the structured clone algorithm can run script as
-    // part of the "own" "deep clone" sub-steps, so we need an AutoEntryScript.
-    // http://www.whatwg.org/specs/web-apps/current-work/#internal-structured-cloning-algorithm
-    nsIGlobalObject* nativeGlobal =
-      xpc::NativeGlobal(js::GetGlobalForObjectCrossCompartment(&aData.toObject()));
-    dom::AutoEntryScript aes(nativeGlobal);
-    success = JS_WriteStructuredClone(aes.cx(), aData, &jsBytes, &mSize,
+    success = JS_WriteStructuredClone(aCx, aData, &jsBytes, &mSize,
                                       nullptr, nullptr,
                                       JS::UndefinedHandleValue);
   }
   NS_ENSURE_STATE(success);
   NS_ENSURE_STATE(jsBytes);
 
   // Copy jsBytes into our own buffer.
   mData = (uint64_t*) malloc(mSize);
--- a/dom/base/nsTextFragment.h
+++ b/dom/base/nsTextFragment.h
@@ -129,18 +129,19 @@ public:
       aString.AllocFailed(aString.Length() + GetLength());
     }
   }
 
   /**
    * Append the contents of this string fragment to aString
    * @return false if an out of memory condition is detected, true otherwise
    */
+  MOZ_WARN_UNUSED_RESULT
   bool AppendTo(nsAString& aString,
-                const mozilla::fallible_t& aFallible) const NS_WARN_UNUSED_RESULT {
+                const mozilla::fallible_t& aFallible) const {
     if (mState.mIs2b) {
       bool ok = aString.Append(m2b, mState.mLength, aFallible);
       if (!ok) {
         return false;
       }
 
       return true;
     } else {
@@ -162,18 +163,19 @@ public:
 
   /**
    * Append a substring of the contents of this string fragment to aString.
    * @param aString the string in which to append
    * @param aOffset where to start the substring in this text fragment
    * @param aLength the length of the substring
    * @return false if an out of memory condition is detected, true otherwise
    */
+  MOZ_WARN_UNUSED_RESULT
   bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength,
-                const mozilla::fallible_t& aFallible) const NS_WARN_UNUSED_RESULT
+                const mozilla::fallible_t& aFallible) const
   {
     if (mState.mIs2b) {
       bool ok = aString.Append(m2b + aOffset, aLength, aFallible);
       if (!ok) {
         return false;
       }
 
       return true;
--- a/dom/base/nsXHTMLContentSerializer.h
+++ b/dom/base/nsXHTMLContentSerializer.h
@@ -41,23 +41,23 @@ class nsXHTMLContentSerializer : public 
  protected:
 
 
   virtual bool CheckElementStart(nsIContent * aContent,
                           bool & aForceFormat,
                           nsAString& aStr,
                           nsresult& aResult) override;
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool AppendEndOfElementStart(nsIContent *aOriginalElement,
                                nsIAtom * aName,
                                int32_t aNamespaceID,
                                nsAString& aStr) override;
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool AfterElementStart(nsIContent* aContent,
                                  nsIContent* aOriginalElement,
                                  nsAString& aStr) override;
 
   virtual bool CheckElementEnd(nsIContent * aContent,
                           bool & aForceFormat,
                           nsAString& aStr) override;
 
@@ -70,35 +70,35 @@ class nsXHTMLContentSerializer : public 
   virtual bool LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aName) override;
 
   bool HasLongLines(const nsString& text, int32_t& aLastNewlineOffset);
 
   // functions to check if we enter in or leave from a preformated content
   virtual void MaybeEnterInPreContent(nsIContent* aNode) override;
   virtual void MaybeLeaveFromPreContent(nsIContent* aNode) override;
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool SerializeAttributes(nsIContent* aContent,
                            nsIContent *aOriginalElement,
                            nsAString& aTagPrefix,
                            const nsAString& aTagNamespaceURI,
                            nsIAtom* aTagName,
                            nsAString& aStr,
                            uint32_t aSkipAttr,
                            bool aAddNSAttr) override;
 
   bool IsFirstChildOfOL(nsIContent* aElement);
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool SerializeLIValueAttribute(nsIContent* aElement,
                                  nsAString& aStr);
   bool IsShorthandAttr(const nsIAtom* aAttrName,
                          const nsIAtom* aElementName);
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool AppendAndTranslateEntities(const nsAString& aStr,
                                           nsAString& aOutputStr) override;
 
   nsresult EscapeURI(nsIContent* aContent,
                      const nsAString& aURI,
                      nsAString& aEscapedURI);
 
 private:
--- a/dom/base/nsXMLContentSerializer.h
+++ b/dom/base/nsXMLContentSerializer.h
@@ -67,92 +67,92 @@ class nsXMLContentSerializer : public ns
                                  nsAString& aStr) override;
 
  protected:
   virtual ~nsXMLContentSerializer();
 
   /**
    * Appends a char16_t character and increments the column position
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendToString(const char16_t aChar,
                       nsAString& aOutputStr);
 
   /**
    * Appends a nsAString string and increments the column position
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendToString(const nsAString& aStr,
                       nsAString& aOutputStr);
 
   /**
    * Appends a string by replacing all line-endings
    * by mLineBreak, except in the case of raw output.
    * It increments the column position.
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendToStringConvertLF(const nsAString& aStr,
                                nsAString& aOutputStr);
 
   /**
    * Appends a string by wrapping it when necessary.
    * It updates the column position.
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendToStringWrapped(const nsASingleFragmentString& aStr,
                              nsAString& aOutputStr);
 
   /**
    * Appends a string by formating and wrapping it when necessary
    * It updates the column position.
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendToStringFormatedWrapped(const nsASingleFragmentString& aStr,
                                      nsAString& aOutputStr);
 
   // used by AppendToStringWrapped
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendWrapped_WhitespaceSequence(
           nsASingleFragmentString::const_char_iterator &aPos,
           const nsASingleFragmentString::const_char_iterator aEnd,
           const nsASingleFragmentString::const_char_iterator aSequenceStart,
           nsAString &aOutputStr);
 
   // used by AppendToStringFormatedWrapped
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendFormatedWrapped_WhitespaceSequence(
           nsASingleFragmentString::const_char_iterator &aPos,
           const nsASingleFragmentString::const_char_iterator aEnd,
           const nsASingleFragmentString::const_char_iterator aSequenceStart,
           bool &aMayIgnoreStartOfLineWhitespaceSequence,
           nsAString &aOutputStr);
 
   // used by AppendToStringWrapped and AppendToStringFormatedWrapped
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendWrapped_NonWhitespaceSequence(
           nsASingleFragmentString::const_char_iterator &aPos,
           const nsASingleFragmentString::const_char_iterator aEnd,
           const nsASingleFragmentString::const_char_iterator aSequenceStart,
           bool &aMayIgnoreStartOfLineWhitespaceSequence,
           bool &aSequenceStartAfterAWhiteSpace,
           nsAString &aOutputStr);
 
   /**
    * add mLineBreak to the string
    * It updates the column position and other flags.
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendNewLineToString(nsAString& aOutputStr);
 
 
   /**
    * Appends a string by translating entities
    * It doesn't increment the column position
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool AppendAndTranslateEntities(const nsAString& aStr,
                                           nsAString& aOutputStr);
 
   /**
    * retrieve the text content of the node and append it to the given string
    * It doesn't increment the column position
    */
   nsresult AppendTextData(nsIContent* aNode,
@@ -192,27 +192,27 @@ class nsXMLContentSerializer : public ns
    * GenerateNewPrefix generates a new prefix and writes it to aPrefix
    */
   void GenerateNewPrefix(nsAString& aPrefix);
 
   uint32_t ScanNamespaceDeclarations(nsIContent* aContent,
                                      nsIContent *aOriginalElement,
                                      const nsAString& aTagNamespaceURI);
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool SerializeAttributes(nsIContent* aContent,
                                    nsIContent *aOriginalElement,
                                    nsAString& aTagPrefix,
                                    const nsAString& aTagNamespaceURI,
                                    nsIAtom* aTagName,
                                    nsAString& aStr,
                                    uint32_t aSkipAttr,
                                    bool aAddNSAttr);
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool SerializeAttr(const nsAString& aPrefix,
                      const nsAString& aName,
                      const nsAString& aValue,
                      nsAString& aStr,
                      bool aDoEscapeEntities);
 
   bool IsJavaScript(nsIContent * aContent,
                       nsIAtom* aAttrNameAtom,
@@ -231,28 +231,28 @@ class nsXMLContentSerializer : public ns
                                    bool & aForceFormat,
                                    nsAString& aStr,
                                    nsresult& aResult);
 
   /**
    * this method is responsible to finish the start tag,
    * in particulary to append the "greater than" sign
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool AppendEndOfElementStart(nsIContent *aOriginalElement,
                                        nsIAtom * aName,
                                        int32_t aNamespaceID,
                                        nsAString& aStr);
 
   /**
    * This method can be redefine to serialize additional things just after
    * after the serialization ot the start tag.
    * (called at the end of AppendElementStart)
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   virtual bool AfterElementStart(nsIContent* aContent,
                                  nsIContent* aOriginalElement,
                                  nsAString& aStr) { return true; };
 
   /**
    * This method can be redefined to check if the element can be serialized.
    * It is called when the serialization of the end tag is asked 
    * (AppendElementEnd)
@@ -291,26 +291,26 @@ class nsXMLContentSerializer : public ns
    * Returns true if a line break should be inserted after an element close tag
    */
   virtual bool LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aName);
 
   /**
    * add intendation. Call only in the case of formating and if the current
    * position is at 0. It updates the column position.
    */
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool AppendIndentation(nsAString& aStr);
 
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool IncrIndentation(nsIAtom* aName);
   void DecrIndentation(nsIAtom* aName);
 
   // Functions to check for newlines that needs to be added between nodes in
   // the root of a document. See mAddNewlineForRootNode
-  NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
   bool MaybeAddNewlineForRootNode(nsAString& aStr);
   void MaybeFlagNewlineForRootNode(nsINode* aNode);
 
   // Functions to check if we enter in or leave from a preformated content
   virtual void MaybeEnterInPreContent(nsIContent* aNode);
   virtual void MaybeLeaveFromPreContent(nsIContent* aNode);
 
   bool ShouldMaintainPreLevel() const;
--- a/dom/base/test/websocket_hybi/mochitest.ini
+++ b/dom/base/test/websocket_hybi/mochitest.ini
@@ -1,14 +1,13 @@
 [DEFAULT]
-skip-if = e10s
 support-files =
   file_binary-frames_wsh.py
   file_check-binary-messages_wsh.py
 
 [test_receive-arraybuffer.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android'
 [test_receive-blob.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android'
 [test_send-arraybuffer.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android'
 [test_send-blob.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android'
+skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
--- a/dom/battery/test/mochitest.ini
+++ b/dom/battery/test/mochitest.ini
@@ -1,5 +1,2 @@
-[DEFAULT]
-skip-if = e10s
-
 [test_battery_basics.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -10441,17 +10441,17 @@ class CGDOMJSProxyHandler_delete(ClassMe
                                     "that has unforgeables.  Figure out how "
                                     "that should work!")
                 # See if the deleter method is fallible.
                 t = deleter.signatures()[0][0]
                 if t.isPrimitive() and not t.nullable() and t.tag() == IDLType.Tags.bool:
                     # The deleter method has a boolean out-parameter. When a
                     # property is found, the out-param indicates whether it was
                     # successfully deleted.
-                    decls = "bool result;\n"
+                    decls = ""
                     if foundVar is None:
                         foundVar = "found"
                         decls += "bool found = false;\n"
                     setDS = fill(
                         """
                         if (!${foundVar}) {
                           deleteSucceeded = true;
                         }
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -61,26 +61,25 @@ public:
 #endif
 
   ErrorResult(ErrorResult&& aRHS)
   {
     *this = Move(aRHS);
   }
   ErrorResult& operator=(ErrorResult&& aRHS);
 
+  explicit ErrorResult(nsresult aRv)
+    : ErrorResult()
+  {
+    AssignErrorCode(aRv);
+  }
+
   void Throw(nsresult rv) {
     MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
-    MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
-    MOZ_ASSERT(rv != NS_ERROR_RANGE_ERR, "Use ThrowRangeError()");
-    MOZ_ASSERT(!IsErrorWithMessage(), "Don't overwrite errors with message");
-    MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
-    MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
-    MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
-    MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
-    mResult = rv;
+    AssignErrorCode(rv);
   }
 
   void ThrowTypeError(const dom::ErrNum errorNumber, ...);
   void ThrowRangeError(const dom::ErrNum errorNumber, ...);
   void ReportErrorWithMessage(JSContext* cx);
   void ClearMessage();
   bool IsErrorWithMessage() const { return ErrorCode() == NS_ERROR_TYPE_ERR || ErrorCode() == NS_ERROR_RANGE_ERR; }
 
@@ -136,66 +135,71 @@ public:
   // In the future, we can add overloads of Throw that take more
   // interesting things, like strings or DOM exception types or
   // something if desired.
 
   // Backwards-compat to make conversion simpler.  We don't call
   // Throw() here because people can easily pass success codes to
   // this.
   void operator=(nsresult rv) {
-    MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
-    MOZ_ASSERT(rv != NS_ERROR_RANGE_ERR, "Use ThrowRangeError()");
-    MOZ_ASSERT(!IsErrorWithMessage(), "Don't overwrite errors with message");
-    MOZ_ASSERT(rv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
-    MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
-    MOZ_ASSERT(rv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
-    MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
-    mResult = rv;
+    AssignErrorCode(rv);
   }
 
   bool Failed() const {
     return NS_FAILED(mResult);
   }
 
   nsresult ErrorCode() const {
     return mResult;
   }
 
 private:
+  friend struct IPC::ParamTraits<ErrorResult>;
+  void SerializeMessage(IPC::Message* aMsg) const;
+  bool DeserializeMessage(const IPC::Message* aMsg, void** aIter);
+
+  void ThrowErrorWithMessage(va_list ap, const dom::ErrNum errorNumber,
+                             nsresult errorType);
+
+  void AssignErrorCode(nsresult aRv) {
+    MOZ_ASSERT(aRv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
+    MOZ_ASSERT(aRv != NS_ERROR_RANGE_ERR, "Use ThrowRangeError()");
+    MOZ_ASSERT(!IsErrorWithMessage(), "Don't overwrite errors with message");
+    MOZ_ASSERT(aRv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
+    MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
+    MOZ_ASSERT(aRv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
+    MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
+    mResult = aRv;
+  }
+
   nsresult mResult;
   struct Message;
   // mMessage is set by ThrowErrorWithMessage and cleared (and deallocated) by
   // ReportErrorWithMessage.
   // mJSException is set (and rooted) by ThrowJSException and unrooted
   // by ReportJSException.
   union {
     Message* mMessage; // valid when IsErrorWithMessage()
     JS::Value mJSException; // valid when IsJSException()
   };
 
-  friend struct IPC::ParamTraits<ErrorResult>;
-  void SerializeMessage(IPC::Message* aMsg) const;
-  bool DeserializeMessage(const IPC::Message* aMsg, void** aIter);
-
 #ifdef DEBUG
   // Used to keep track of codepaths that might throw JS exceptions,
   // for assertion purposes.
   bool mMightHaveUnreportedJSException;
   // Used to keep track of whether mMessage has ever been assigned to.
   // We need to check this in order to ensure that not attempting to
   // delete mMessage in DeserializeMessage doesn't leak memory.
   bool mHasMessage;
 #endif
 
   // Not to be implemented, to make sure people always pass this by
   // reference, not by value.
   ErrorResult(const ErrorResult&) = delete;
   void operator=(const ErrorResult&) = delete;
-  void ThrowErrorWithMessage(va_list ap, const dom::ErrNum errorNumber,
-                             nsresult errorType);
 };
 
 /******************************************************************************
  ** Macros for checking results
  ******************************************************************************/
 
 #define ENSURE_SUCCESS(res, ret)                                          \
   do {                                                                    \
--- a/dom/bindings/MozMap.h
+++ b/dom/bindings/MozMap.h
@@ -12,16 +12,17 @@
 
 #ifndef mozilla_dom_MozMap_h
 #define mozilla_dom_MozMap_h
 
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/Move.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace binding_detail {
 template<typename DataType>
 class MozMapEntry : public nsStringHashKey
@@ -95,17 +96,18 @@ public:
   // with a dependency on BindingUtils.h here for the SequenceTracer bits.
   typedef PLDHashOperator (* Enumerator)(DataType* aValue, void* aClosure);
   void EnumerateValues(Enumerator aEnumerator, void *aClosure)
   {
     ValueEnumClosure args = { aEnumerator, aClosure };
     this->EnumerateEntries(ValueEnumerator, &args);
   }
 
-  DataType* AddEntry(const nsAString& aKey) NS_WARN_UNUSED_RESULT
+  MOZ_WARN_UNUSED_RESULT
+  DataType* AddEntry(const nsAString& aKey)
   {
     EntryType* ent = this->PutEntry(aKey, fallible);
     if (!ent) {
       return nullptr;
     }
     return &ent->mData;
   }
 
--- a/dom/cache/ActorChild.cpp
+++ b/dom/cache/ActorChild.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "mozilla/dom/cache/ActorChild.h"
 
 #include "mozilla/dom/cache/Feature.h"
+#include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 void
 ActorChild::SetFeature(Feature* aFeature)
 {
@@ -27,16 +28,17 @@ ActorChild::SetFeature(Feature* aFeature
   if (mFeature) {
     mFeature->AddActor(this);
   }
 }
 
 void
 ActorChild::RemoveFeature()
 {
+  MOZ_ASSERT_IF(!NS_IsMainThread(), mFeature);
   if (mFeature) {
     mFeature->RemoveActor(this);
     mFeature = nullptr;
   }
 }
 
 Feature*
 ActorChild::GetFeature() const
--- a/dom/cache/AutoUtils.cpp
+++ b/dom/cache/AutoUtils.cpp
@@ -2,45 +2,46 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "mozilla/dom/cache/AutoUtils.h"
 
 #include "mozilla/unused.h"
+#include "mozilla/dom/cache/CacheParent.h"
 #include "mozilla/dom/cache/CachePushStreamChild.h"
 #include "mozilla/dom/cache/CacheStreamControlParent.h"
 #include "mozilla/dom/cache/ReadStream.h"
 #include "mozilla/dom/cache/SavedTypes.h"
 #include "mozilla/dom/cache/StreamList.h"
 #include "mozilla/dom/cache/TypeUtils.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/PBackgroundParent.h"
 
 namespace {
 
 using mozilla::unused;
 using mozilla::dom::cache::CachePushStreamChild;
-using mozilla::dom::cache::PCacheReadStream;
-using mozilla::dom::cache::PCacheReadStreamOrVoid;
+using mozilla::dom::cache::CacheReadStream;
+using mozilla::dom::cache::CacheReadStreamOrVoid;
 using mozilla::ipc::FileDescriptor;
 using mozilla::ipc::FileDescriptorSetChild;
 using mozilla::ipc::FileDescriptorSetParent;
 using mozilla::ipc::OptionalFileDescriptorSet;
 
 enum CleanupAction
 {
   Forget,
   Delete
 };
 
 void
-CleanupChildFds(PCacheReadStream& aReadStream, CleanupAction aAction)
+CleanupChildFds(CacheReadStream& aReadStream, CleanupAction aAction)
 {
   if (aReadStream.fds().type() !=
       OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
     return;
   }
 
   nsAutoTArray<FileDescriptor, 4> fds;
 
@@ -54,17 +55,17 @@ CleanupChildFds(PCacheReadStream& aReadS
 
   // FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
   // unconditionally forget them here.  The fds themselves are auto-closed in
   // ~FileDescriptor since they originated in this process.
   fdSetActor->ForgetFileDescriptors(fds);
 }
 
 void
-CleanupChildPushStream(PCacheReadStream& aReadStream, CleanupAction aAction)
+CleanupChildPushStream(CacheReadStream& aReadStream, CleanupAction aAction)
 {
   if (!aReadStream.pushStreamChild()) {
     return;
   }
 
   auto pushStream =
     static_cast<CachePushStreamChild*>(aReadStream.pushStreamChild());
 
@@ -73,34 +74,34 @@ CleanupChildPushStream(PCacheReadStream&
     return;
   }
 
   // If we send the stream, then we need to start it before forgetting about it.
   pushStream->Start();
 }
 
 void
-CleanupChild(PCacheReadStream& aReadStream, CleanupAction aAction)
+CleanupChild(CacheReadStream& aReadStream, CleanupAction aAction)
 {
   CleanupChildFds(aReadStream, aAction);
   CleanupChildPushStream(aReadStream, aAction);
 }
 
 void
-CleanupChild(PCacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
+CleanupChild(CacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
 {
-  if (aReadStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
+  if (aReadStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
     return;
   }
 
-  CleanupChild(aReadStreamOrVoid.get_PCacheReadStream(), aAction);
+  CleanupChild(aReadStreamOrVoid.get_CacheReadStream(), aAction);
 }
 
 void
-CleanupParentFds(PCacheReadStream& aReadStream, CleanupAction aAction)
+CleanupParentFds(CacheReadStream& aReadStream, CleanupAction aAction)
 {
   if (aReadStream.fds().type() !=
       OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
     return;
   }
 
   nsAutoTArray<FileDescriptor, 4> fds;
 
@@ -114,198 +115,408 @@ CleanupParentFds(PCacheReadStream& aRead
 
   // FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
   // unconditionally forget them here.  The fds themselves are auto-closed in
   // ~FileDescriptor since they originated in this process.
   fdSetActor->ForgetFileDescriptors(fds);
 }
 
 void
-CleanupParentFds(PCacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
+CleanupParentFds(CacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
 {
-  if (aReadStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
+  if (aReadStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
     return;
   }
 
-  CleanupParentFds(aReadStreamOrVoid.get_PCacheReadStream(), aAction);
+  CleanupParentFds(aReadStreamOrVoid.get_CacheReadStream(), aAction);
 }
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 using mozilla::ipc::PBackgroundParent;
 
-AutoChildBase::AutoChildBase(TypeUtils* aTypeUtils)
+// --------------------------------------------
+
+AutoChildOpArgs::AutoChildOpArgs(TypeUtils* aTypeUtils,
+                                 const CacheOpArgs& aOpArgs)
   : mTypeUtils(aTypeUtils)
+  , mOpArgs(aOpArgs)
   , mSent(false)
 {
   MOZ_ASSERT(mTypeUtils);
 }
 
-AutoChildBase::~AutoChildBase()
-{
-}
-
-// --------------------------------------------
-
-AutoChildRequest::AutoChildRequest(TypeUtils* aTypeUtils)
-  : AutoChildBase(aTypeUtils)
-{
-  mRequestOrVoid = void_t();
-}
-
-AutoChildRequest::~AutoChildRequest()
-{
-  if (mRequestOrVoid.type() != PCacheRequestOrVoid::TPCacheRequest) {
-    return;
-  }
-
-  CleanupAction action = mSent ? Forget : Delete;
-  CleanupChild(mRequestOrVoid.get_PCacheRequest().body(), action);
-}
-
-void
-AutoChildRequest::Add(InternalRequest* aRequest, BodyAction aBodyAction,
-                      ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
-                      ErrorResult& aRv)
-{
-  MOZ_ASSERT(!mSent);
-  MOZ_ASSERT(mRequestOrVoid.type() == PCacheRequestOrVoid::Tvoid_t);
-  mRequestOrVoid = PCacheRequest();
-  mTypeUtils->ToPCacheRequest(mRequestOrVoid.get_PCacheRequest(), aRequest,
-                              aBodyAction, aReferrerAction, aSchemeAction, aRv);
-}
-
-const PCacheRequest&
-AutoChildRequest::SendAsRequest()
-{
-  MOZ_ASSERT(mRequestOrVoid.type() == PCacheRequestOrVoid::TPCacheRequest);
-  return mRequestOrVoid.get_PCacheRequest();
-}
-
-const PCacheRequestOrVoid&
-AutoChildRequest::SendAsRequestOrVoid()
-{
-  return mRequestOrVoid;
-}
-
-// --------------------------------------------
-
-AutoChildRequestList::AutoChildRequestList(TypeUtils* aTypeUtils,
-                                           uint32_t aCapacity)
-  : AutoChildBase(aTypeUtils)
-{
-  mRequestList.SetCapacity(aCapacity);
-}
-
-AutoChildRequestList::~AutoChildRequestList()
+AutoChildOpArgs::~AutoChildOpArgs()
 {
   CleanupAction action = mSent ? Forget : Delete;
-  for (uint32_t i = 0; i < mRequestList.Length(); ++i) {
-    CleanupChild(mRequestList[i].body(), action);
+
+  switch(mOpArgs.type()) {
+    case CacheOpArgs::TCacheMatchArgs:
+    {
+      CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
+      CleanupChild(args.request().body(), action);
+      break;
+    }
+    case CacheOpArgs::TCacheMatchAllArgs:
+    {
+      CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs();
+      if (args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t) {
+        break;
+      }
+      CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action);
+      break;
+    }
+    case CacheOpArgs::TCacheAddAllArgs:
+    {
+      CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
+      auto& list = args.requestList();
+      for (uint32_t i = 0; i < list.Length(); ++i) {
+        CleanupChild(list[i].body(), action);
+      }
+      break;
+    }
+    case CacheOpArgs::TCachePutAllArgs:
+    {
+      CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
+      auto& list = args.requestResponseList();
+      for (uint32_t i = 0; i < list.Length(); ++i) {
+        CleanupChild(list[i].request().body(), action);
+        CleanupChild(list[i].response().body(), action);
+      }
+      break;
+    }
+    case CacheOpArgs::TCacheDeleteArgs:
+    {
+      CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
+      CleanupChild(args.request().body(), action);
+      break;
+    }
+    case CacheOpArgs::TCacheKeysArgs:
+    {
+      CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs();
+      if (args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t) {
+        break;
+      }
+      CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action);
+      break;
+    }
+    case CacheOpArgs::TStorageMatchArgs:
+    {
+      StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
+      CleanupChild(args.request().body(), action);
+      break;
+    }
+    default:
+      // Other types do not need cleanup
+      break;
   }
 }
 
 void
-AutoChildRequestList::Add(InternalRequest* aRequest, BodyAction aBodyAction,
-                          ReferrerAction aReferrerAction,
-                          SchemeAction aSchemeAction, ErrorResult& aRv)
+AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
+                     ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
+                     ErrorResult& aRv)
 {
   MOZ_ASSERT(!mSent);
 
-  // The FileDescriptorSetChild asserts in its destructor that all fds have
-  // been removed.  The copy constructor, however, simply duplicates the
-  // fds without removing any.  This means each temporary and copy must be
-  // explicitly cleaned up.
-  //
-  // Avoid a lot of this hassle by making sure we only create one here.  On
-  // error we remove it.
+  switch(mOpArgs.type()) {
+    case CacheOpArgs::TCacheMatchArgs:
+    {
+      CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
+      mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
+                                  aReferrerAction, aSchemeAction, aRv);
+      break;
+    }
+    case CacheOpArgs::TCacheMatchAllArgs:
+    {
+      CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs();
+      MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
+      args.requestOrVoid() = CacheRequest();
+      mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
+                                  aRequest, aBodyAction, aReferrerAction,
+                                  aSchemeAction, aRv);
+      break;
+    }
+    case CacheOpArgs::TCacheAddAllArgs:
+    {
+      CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
+
+      // The FileDescriptorSetChild asserts in its destructor that all fds have
+      // been removed.  The copy constructor, however, simply duplicates the
+      // fds without removing any.  This means each temporary and copy must be
+      // explicitly cleaned up.
+      //
+      // Avoid a lot of this hassle by making sure we only create one here.  On
+      // error we remove it.
+      CacheRequest& request = *args.requestList().AppendElement();
 
-  PCacheRequest* request = mRequestList.AppendElement();
-  mTypeUtils->ToPCacheRequest(*request, aRequest, aBodyAction, aReferrerAction,
-                              aSchemeAction, aRv);
-  if (aRv.Failed()) {
-    mRequestList.RemoveElementAt(mRequestList.Length() - 1);
+      mTypeUtils->ToCacheRequest(request, aRequest, aBodyAction,
+                                  aReferrerAction, aSchemeAction, aRv);
+      if (aRv.Failed()) {
+        args.requestList().RemoveElementAt(args.requestList().Length() - 1);
+      }
+      break;
+    }
+    case CacheOpArgs::TCacheDeleteArgs:
+    {
+      CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
+      mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
+                                  aReferrerAction, aSchemeAction, aRv);
+      break;
+    }
+    case CacheOpArgs::TCacheKeysArgs:
+    {
+      CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs();
+      MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
+      args.requestOrVoid() = CacheRequest();
+      mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
+                                  aRequest, aBodyAction, aReferrerAction,
+                                  aSchemeAction, aRv);
+      break;
+    }
+    case CacheOpArgs::TStorageMatchArgs:
+    {
+      StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
+      mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
+                                  aReferrerAction, aSchemeAction, aRv);
+      break;
+    }
+    default:
+      MOZ_CRASH("Cache args type cannot send a Request!");
   }
 }
 
-const nsTArray<PCacheRequest>&
-AutoChildRequestList::SendAsRequestList()
+void
+AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
+                     ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
+                     Response& aResponse, ErrorResult& aRv)
+{
+  MOZ_ASSERT(!mSent);
+
+  switch(mOpArgs.type()) {
+    case CacheOpArgs::TCachePutAllArgs:
+    {
+      CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
+
+      // The FileDescriptorSetChild asserts in its destructor that all fds have
+      // been removed.  The copy constructor, however, simply duplicates the
+      // fds without removing any.  This means each temporary and copy must be
+      // explicitly cleaned up.
+      //
+      // Avoid a lot of this hassle by making sure we only create one here.  On
+      // error we remove it.
+      CacheRequestResponse& pair = *args.requestResponseList().AppendElement();
+      pair.request().body() = void_t();
+      pair.response().body() = void_t();
+
+      mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction,
+                                  aReferrerAction, aSchemeAction, aRv);
+      if (!aRv.Failed()) {
+        mTypeUtils->ToCacheResponse(pair.response(), aResponse, aRv);
+      }
+
+      if (aRv.Failed()) {
+        CleanupChild(pair.request().body(), Delete);
+        args.requestResponseList().RemoveElementAt(
+          args.requestResponseList().Length() - 1);
+      }
+
+      break;
+    }
+    default:
+      MOZ_CRASH("Cache args type cannot send a Request/Response pair!");
+  }
+}
+
+const CacheOpArgs&
+AutoChildOpArgs::SendAsOpArgs()
 {
   MOZ_ASSERT(!mSent);
   mSent = true;
-  return mRequestList;
+  return mOpArgs;
 }
 
 // --------------------------------------------
 
-AutoChildRequestResponse::AutoChildRequestResponse(TypeUtils* aTypeUtils)
-  : AutoChildBase(aTypeUtils)
-{
-  // Default IPC-generated constructor does not initialize these correctly
-  // and we check them later when cleaning up.
-  mRequestResponse.request().body() = void_t();
-  mRequestResponse.response().body() = void_t();
-}
-
-AutoChildRequestResponse::~AutoChildRequestResponse()
-{
-  CleanupAction action = mSent ? Forget : Delete;
-  CleanupChild(mRequestResponse.request().body(), action);
-  CleanupChild(mRequestResponse.response().body(), action);
-}
-
-void
-AutoChildRequestResponse::Add(InternalRequest* aRequest, BodyAction aBodyAction,
-                              ReferrerAction aReferrerAction,
-                              SchemeAction aSchemeAction, ErrorResult& aRv)
-{
-  MOZ_ASSERT(!mSent);
-  mTypeUtils->ToPCacheRequest(mRequestResponse.request(), aRequest, aBodyAction,
-                              aReferrerAction, aSchemeAction, aRv);
-}
-
-void
-AutoChildRequestResponse::Add(Response& aResponse, ErrorResult& aRv)
-{
-  MOZ_ASSERT(!mSent);
-  mTypeUtils->ToPCacheResponse(mRequestResponse.response(), aResponse, aRv);
-}
-
-const CacheRequestResponse&
-AutoChildRequestResponse::SendAsRequestResponse()
-{
-  MOZ_ASSERT(!mSent);
-  mSent = true;
-  return mRequestResponse;
-}
-
-// --------------------------------------------
-
-AutoParentBase::AutoParentBase(PBackgroundParent* aManager)
+AutoParentOpResult::AutoParentOpResult(mozilla::ipc::PBackgroundParent* aManager,
+                                       const CacheOpResult& aOpResult)
   : mManager(aManager)
+  , mOpResult(aOpResult)
   , mStreamControl(nullptr)
   , mSent(false)
 {
   MOZ_ASSERT(mManager);
 }
 
-AutoParentBase::~AutoParentBase()
+AutoParentOpResult::~AutoParentOpResult()
 {
-  if (!mSent && mStreamControl) {
+  CleanupAction action = mSent ? Forget : Delete;
+
+  switch (mOpResult.type()) {
+    case CacheOpResult::TCacheMatchResult:
+    {
+      CacheMatchResult& result = mOpResult.get_CacheMatchResult();
+      if (result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t) {
+        break;
+      }
+      CleanupParentFds(result.responseOrVoid().get_CacheResponse().body(),
+                       action);
+      break;
+    }
+    case CacheOpResult::TCacheMatchAllResult:
+    {
+      CacheMatchAllResult& result = mOpResult.get_CacheMatchAllResult();
+      for (uint32_t i = 0; i < result.responseList().Length(); ++i) {
+        CleanupParentFds(result.responseList()[i].body(), action);
+      }
+      break;
+    }
+    case CacheOpResult::TCacheKeysResult:
+    {
+      CacheKeysResult& result = mOpResult.get_CacheKeysResult();
+      for (uint32_t i = 0; i < result.requestList().Length(); ++i) {
+        CleanupParentFds(result.requestList()[i].body(), action);
+      }
+      break;
+    }
+    case CacheOpResult::TStorageMatchResult:
+    {
+      StorageMatchResult& result = mOpResult.get_StorageMatchResult();
+      if (result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t) {
+        break;
+      }
+      CleanupParentFds(result.responseOrVoid().get_CacheResponse().body(),
+                       action);
+      break;
+    }
+    case CacheOpResult::TStorageOpenResult:
+    {
+      StorageOpenResult& result = mOpResult.get_StorageOpenResult();
+      if (action == Forget || result.actorParent() == nullptr) {
+        break;
+      }
+      unused << PCacheParent::Send__delete__(result.actorParent());
+    }
+    default:
+      // other types do not need clean up
+      break;
+  }
+
+  if (action == Delete && mStreamControl) {
     unused << PCacheStreamControlParent::Send__delete__(mStreamControl);
   }
 }
 
 void
-AutoParentBase::SerializeReadStream(const nsID& aId, StreamList* aStreamList,
-                                    PCacheReadStream* aReadStreamOut)
+AutoParentOpResult::Add(CacheId aOpenedCacheId, Manager* aManager)
+{
+  MOZ_ASSERT(mOpResult.type() == CacheOpResult::TStorageOpenResult);
+  MOZ_ASSERT(mOpResult.get_StorageOpenResult().actorParent() == nullptr);
+  mOpResult.get_StorageOpenResult().actorParent() =
+    mManager->SendPCacheConstructor(new CacheParent(aManager, aOpenedCacheId));
+}
+
+void
+AutoParentOpResult::Add(const SavedResponse& aSavedResponse,
+                        StreamList* aStreamList)
+{
+  MOZ_ASSERT(!mSent);
+
+  switch (mOpResult.type()) {
+    case CacheOpResult::TCacheMatchResult:
+    {
+      CacheMatchResult& result = mOpResult.get_CacheMatchResult();
+      MOZ_ASSERT(result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t);
+      result.responseOrVoid() = aSavedResponse.mValue;
+      SerializeResponseBody(aSavedResponse, aStreamList,
+                            &result.responseOrVoid().get_CacheResponse());
+      break;
+    }
+    case CacheOpResult::TCacheMatchAllResult:
+    {
+      CacheMatchAllResult& result = mOpResult.get_CacheMatchAllResult();
+      result.responseList().AppendElement(aSavedResponse.mValue);
+      SerializeResponseBody(aSavedResponse, aStreamList,
+                            &result.responseList().LastElement());
+      break;
+    }
+    case CacheOpResult::TStorageMatchResult:
+    {
+      StorageMatchResult& result = mOpResult.get_StorageMatchResult();
+      MOZ_ASSERT(result.responseOrVoid().type() == CacheResponseOrVoid::Tvoid_t);
+      result.responseOrVoid() = aSavedResponse.mValue;
+      SerializeResponseBody(aSavedResponse, aStreamList,
+                            &result.responseOrVoid().get_CacheResponse());
+      break;
+    }
+    default:
+      MOZ_CRASH("Cache result type cannot handle returning a Response!");
+  }
+}
+
+void
+AutoParentOpResult::Add(const SavedRequest& aSavedRequest,
+                        StreamList* aStreamList)
+{
+  MOZ_ASSERT(!mSent);
+
+  switch (mOpResult.type()) {
+    case CacheOpResult::TCacheKeysResult:
+    {
+      CacheKeysResult& result = mOpResult.get_CacheKeysResult();
+      result.requestList().AppendElement(aSavedRequest.mValue);
+      CacheRequest& request = result.requestList().LastElement();
+
+      if (!aSavedRequest.mHasBodyId) {
+        request.body() = void_t();
+        break;
+      }
+
+      request.body() = CacheReadStream();
+      SerializeReadStream(aSavedRequest.mBodyId, aStreamList,
+                          &request.body().get_CacheReadStream());
+      break;
+    }
+    default:
+      MOZ_CRASH("Cache result type cannot handle returning a Request!");
+  }
+}
+
+const CacheOpResult&
+AutoParentOpResult::SendAsOpResult()
+{
+  MOZ_ASSERT(!mSent);
+  mSent = true;
+  return mOpResult;
+}
+
+void
+AutoParentOpResult::SerializeResponseBody(const SavedResponse& aSavedResponse,
+                                          StreamList* aStreamList,
+                                          CacheResponse* aResponseOut)
+{
+  MOZ_ASSERT(aResponseOut);
+
+  if (!aSavedResponse.mHasBodyId) {
+    aResponseOut->body() = void_t();
+    return;
+  }
+
+  aResponseOut->body() = CacheReadStream();
+  SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
+                      &aResponseOut->body().get_CacheReadStream());
+}
+
+void
+AutoParentOpResult::SerializeReadStream(const nsID& aId, StreamList* aStreamList,
+                                        CacheReadStream* aReadStreamOut)
 {
   MOZ_ASSERT(aStreamList);
   MOZ_ASSERT(aReadStreamOut);
   MOZ_ASSERT(!mSent);
 
   nsCOMPtr<nsIInputStream> stream = aStreamList->Extract(aId);
   MOZ_ASSERT(stream);
 
@@ -323,144 +534,11 @@ AutoParentBase::SerializeReadStream(cons
 
   aStreamList->SetStreamControl(mStreamControl);
 
   nsRefPtr<ReadStream> readStream = ReadStream::Create(mStreamControl,
                                                        aId, stream);
   readStream->Serialize(aReadStreamOut);
 }
 
-// --------------------------------------------
-
-AutoParentRequestList::AutoParentRequestList(PBackgroundParent* aManager,
-                                             uint32_t aCapacity)
-  : AutoParentBase(aManager)
-{
-  mRequestList.SetCapacity(aCapacity);
-}
-
-AutoParentRequestList::~AutoParentRequestList()
-{
-  CleanupAction action = mSent ? Forget : Delete;
-  for (uint32_t i = 0; i < mRequestList.Length(); ++i) {
-    CleanupParentFds(mRequestList[i].body(), action);
-  }
-}
-
-void
-AutoParentRequestList::Add(const SavedRequest& aSavedRequest,
-                           StreamList* aStreamList)
-{
-  MOZ_ASSERT(!mSent);
-
-  mRequestList.AppendElement(aSavedRequest.mValue);
-  PCacheRequest& request = mRequestList.LastElement();
-
-  if (!aSavedRequest.mHasBodyId) {
-    request.body() = void_t();
-    return;
-  }
-
-  request.body() = PCacheReadStream();
-  SerializeReadStream(aSavedRequest.mBodyId, aStreamList,
-                      &request.body().get_PCacheReadStream());
-}
-
-const nsTArray<PCacheRequest>&
-AutoParentRequestList::SendAsRequestList()
-{
-  MOZ_ASSERT(!mSent);
-  mSent = true;
-  return mRequestList;
-}
-
-// --------------------------------------------
-
-AutoParentResponseList::AutoParentResponseList(PBackgroundParent* aManager,
-                                               uint32_t aCapacity)
-  : AutoParentBase(aManager)
-{
-  mResponseList.SetCapacity(aCapacity);
-}
-
-AutoParentResponseList::~AutoParentResponseList()
-{
-  CleanupAction action = mSent ? Forget : Delete;
-  for (uint32_t i = 0; i < mResponseList.Length(); ++i) {
-    CleanupParentFds(mResponseList[i].body(), action);
-  }
-}
-
-void
-AutoParentResponseList::Add(const SavedResponse& aSavedResponse,
-                            StreamList* aStreamList)
-{
-  MOZ_ASSERT(!mSent);
-
-  mResponseList.AppendElement(aSavedResponse.mValue);
-  PCacheResponse& response = mResponseList.LastElement();
-
-  if (!aSavedResponse.mHasBodyId) {
-    response.body() = void_t();
-    return;
-  }
-
-  response.body() = PCacheReadStream();
-  SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
-                      &response.body().get_PCacheReadStream());
-}
-
-const nsTArray<PCacheResponse>&
-AutoParentResponseList::SendAsResponseList()
-{
-  MOZ_ASSERT(!mSent);
-  mSent = true;
-  return mResponseList;
-}
-
-// --------------------------------------------
-
-AutoParentResponseOrVoid::AutoParentResponseOrVoid(ipc::PBackgroundParent* aManager)
-  : AutoParentBase(aManager)
-{
-  mResponseOrVoid = void_t();
-}
-
-AutoParentResponseOrVoid::~AutoParentResponseOrVoid()
-{
-  if (mResponseOrVoid.type() != PCacheResponseOrVoid::TPCacheResponse) {
-    return;
-  }
-
-  CleanupAction action = mSent ? Forget : Delete;
-  CleanupParentFds(mResponseOrVoid.get_PCacheResponse().body(), action);
-}
-
-void
-AutoParentResponseOrVoid::Add(const SavedResponse& aSavedResponse,
-                              StreamList* aStreamList)
-{
-  MOZ_ASSERT(!mSent);
-
-  mResponseOrVoid = aSavedResponse.mValue;
-  PCacheResponse& response = mResponseOrVoid.get_PCacheResponse();
-
-  if (!aSavedResponse.mHasBodyId) {
-    response.body() = void_t();
-    return;
-  }
-
-  response.body() = PCacheReadStream();
-  SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
-                      &response.body().get_PCacheReadStream());
-}
-
-const PCacheResponseOrVoid&
-AutoParentResponseOrVoid::SendAsResponseOrVoid()
-{
-  MOZ_ASSERT(!mSent);
-  mSent = true;
-  return mResponseOrVoid;
-}
-
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/AutoUtils.h
+++ b/dom/cache/AutoUtils.h
@@ -3,17 +3,18 @@
 /* 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/. */
 
 #ifndef mozilla_dom_cache_AutoUtils_h
 #define mozilla_dom_cache_AutoUtils_h
 
 #include "mozilla/Attributes.h"
-#include "mozilla/dom/cache/PCacheTypes.h"
+#include "mozilla/dom/cache/CacheTypes.h"
+#include "mozilla/dom/cache/Types.h"
 #include "mozilla/dom/cache/TypeUtils.h"
 #include "nsTArray.h"
 
 struct nsID;
 
 namespace mozilla {
 
 class ErrorResult;
@@ -24,150 +25,78 @@ class PBackgroundParent;
 
 namespace dom {
 
 class InternalRequest;
 
 namespace cache {
 
 class CacheStreamControlParent;
+class Manager;
 struct SavedRequest;
 struct SavedResponse;
 class StreamList;
 
 // A collection of RAII-style helper classes to ensure that IPC
 // FileDescriptorSet actors are properly cleaned up.  The user of these actors
 // must manually either Forget() the Fds or Send__delete__() the actor
 // depending on if the descriptors were actually sent.
 //
 // Note, these should only be used when *sending* streams across IPC.  The
 // deserialization case is handled by creating a ReadStream object.
 
-class MOZ_STACK_CLASS AutoChildBase
+class MOZ_STACK_CLASS AutoChildOpArgs final
 {
-protected:
+public:
   typedef TypeUtils::BodyAction BodyAction;
   typedef TypeUtils::ReferrerAction ReferrerAction;
   typedef TypeUtils::SchemeAction SchemeAction;
 
-  AutoChildBase(TypeUtils* aTypeUtils);
-  virtual ~AutoChildBase() = 0;
-
-  TypeUtils* mTypeUtils;
-  bool mSent;
-};
-
-class MOZ_STACK_CLASS AutoChildRequest final : public AutoChildBase
-{
-public:
-  explicit AutoChildRequest(TypeUtils* aTypeUtils);
-  ~AutoChildRequest();
-
-  void Add(InternalRequest* aRequest, BodyAction aBodyAction,
-           ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
-           ErrorResult& aRv);
-
-  const PCacheRequest& SendAsRequest();
-  const PCacheRequestOrVoid& SendAsRequestOrVoid();
-
-private:
-  PCacheRequestOrVoid mRequestOrVoid;
-};
-
-class MOZ_STACK_CLASS AutoChildRequestList final : public AutoChildBase
-{
-public:
-  AutoChildRequestList(TypeUtils* aTypeUtils, uint32_t aCapacity);
-  ~AutoChildRequestList();
-
-  void Add(InternalRequest* aRequest, BodyAction aBodyAction,
-           ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
-           ErrorResult& aRv);
-
-  const nsTArray<PCacheRequest>& SendAsRequestList();
-
-private:
-  // Allocates ~5k inline in the stack-only class
-  nsAutoTArray<PCacheRequest, 32> mRequestList;
-};
-
-class MOZ_STACK_CLASS AutoChildRequestResponse final : public AutoChildBase
-{
-public:
-  explicit AutoChildRequestResponse(TypeUtils* aTypeUtils);
-  ~AutoChildRequestResponse();
+  AutoChildOpArgs(TypeUtils* aTypeUtils, const CacheOpArgs& aOpArgs);
+  ~AutoChildOpArgs();
 
   void Add(InternalRequest* aRequest, BodyAction aBodyAction,
            ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
            ErrorResult& aRv);
-  void Add(Response& aResponse, ErrorResult& aRv);
+  void Add(InternalRequest* aRequest, BodyAction aBodyAction,
+           ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
+           Response& aResponse, ErrorResult& aRv);
 
-  const CacheRequestResponse& SendAsRequestResponse();
+  const CacheOpArgs& SendAsOpArgs();
 
 private:
-  CacheRequestResponse mRequestResponse;
-};
-
-class MOZ_STACK_CLASS AutoParentBase
-{
-protected:
-  explicit AutoParentBase(mozilla::ipc::PBackgroundParent* aManager);
-  virtual ~AutoParentBase() = 0;
-
-  void SerializeReadStream(const nsID& aId, StreamList* aStreamList,
-                           PCacheReadStream* aReadStreamOut);
-
-  mozilla::ipc::PBackgroundParent* mManager;
-  CacheStreamControlParent* mStreamControl;
+  TypeUtils* mTypeUtils;
+  CacheOpArgs mOpArgs;
   bool mSent;
 };
 
-class MOZ_STACK_CLASS AutoParentRequestList final : public AutoParentBase
-{
-public:
-  AutoParentRequestList(mozilla::ipc::PBackgroundParent* aManager,
-                        uint32_t aCapacity);
-  ~AutoParentRequestList();
-
-  void Add(const SavedRequest& aSavedRequest, StreamList* aStreamList);
-
-  const nsTArray<PCacheRequest>& SendAsRequestList();
-
-private:
-  // Allocates ~5k inline in the stack-only class
-  nsAutoTArray<PCacheRequest, 32> mRequestList;
-};
-
-class MOZ_STACK_CLASS AutoParentResponseList final : public AutoParentBase
+class MOZ_STACK_CLASS AutoParentOpResult final
 {
 public:
-  AutoParentResponseList(mozilla::ipc::PBackgroundParent* aManager,
-                         uint32_t aCapacity);
-  ~AutoParentResponseList();
+  AutoParentOpResult(mozilla::ipc::PBackgroundParent* aManager,
+                     const CacheOpResult& aOpResult);
+  ~AutoParentOpResult();
 
+  void Add(CacheId aOpenedCacheId, Manager* aManager);
   void Add(const SavedResponse& aSavedResponse, StreamList* aStreamList);
+  void Add(const SavedRequest& aSavedRequest, StreamList* aStreamList);
 
-  const nsTArray<PCacheResponse>& SendAsResponseList();
+  const CacheOpResult& SendAsOpResult();
 
 private:
-  // Allocates ~4k inline in the stack-only class
-  nsAutoTArray<PCacheResponse, 32> mResponseList;
-};
+  void SerializeResponseBody(const SavedResponse& aSavedResponse,
+                             StreamList* aStreamList,
+                             CacheResponse* aResponseOut);
 
-class MOZ_STACK_CLASS AutoParentResponseOrVoid final : public AutoParentBase
-{
-public:
-  explicit AutoParentResponseOrVoid(mozilla::ipc::PBackgroundParent* aManager);
-  ~AutoParentResponseOrVoid();
+  void SerializeReadStream(const nsID& aId, StreamList* aStreamList,
+                           CacheReadStream* aReadStreamOut);
 
-  void Add(const SavedResponse& aSavedResponse, StreamList* aStreamList);
-
-  const PCacheResponseOrVoid& SendAsResponseOrVoid();
-
-private:
-  PCacheResponseOrVoid mResponseOrVoid;
+  mozilla::ipc::PBackgroundParent* mManager;
+  CacheOpResult mOpResult;
+  CacheStreamControlParent* mStreamControl;
+  bool mSent;
 };
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_cache_AutoUtils_h
--- a/dom/cache/Cache.cpp
+++ b/dom/cache/Cache.cpp
@@ -11,17 +11,16 @@
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/CacheBinding.h"
 #include "mozilla/dom/cache/AutoUtils.h"
 #include "mozilla/dom/cache/CacheChild.h"
 #include "mozilla/dom/cache/CachePushStreamChild.h"
 #include "mozilla/dom/cache/ReadStream.h"
-#include "mozilla/dom/cache/TypeUtils.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/unused.h"
 #include "nsIGlobalObject.h"
 #include "nsNetUtil.h"
 
 namespace {
 
@@ -74,27 +73,17 @@ namespace cache {
 
 using mozilla::ErrorResult;
 using mozilla::unused;
 using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
 using mozilla::dom::workers::WorkerPrivate;
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::Cache);
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::Cache);
-NS_IMPL_CYCLE_COLLECTION_CLASS(mozilla::dom::cache::Cache)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(mozilla::dom::cache::Cache)
-  tmp->DisconnectFromActor();
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal, mRequestPromises)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(mozilla::dom::cache::Cache)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal, mRequestPromises)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(mozilla::dom::cache::Cache)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::cache::Cache, mGlobal);
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Cache)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 Cache::Cache(nsIGlobalObject* aGlobal, CacheChild* aActor)
   : mGlobal(aGlobal)
@@ -106,260 +95,199 @@ Cache::Cache(nsIGlobalObject* aGlobal, C
 }
 
 already_AddRefed<Promise>
 Cache::Match(const RequestOrUSVString& aRequest,
              const CacheQueryOptions& aOptions, ErrorResult& aRv)
 {
   MOZ_ASSERT(mActor);
 
-  nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
-  if (!promise) {
-    return nullptr;
-  }
-
   nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
-  if (aRv.Failed()) {
+  if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  AutoChildRequest request(this);
+  CacheQueryParams params;
+  ToCacheQueryParams(params, aOptions);
 
-  request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
-  if (aRv.Failed()) {
+  AutoChildOpArgs args(this, CacheMatchArgs(CacheRequest(), params));
+
+  args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
-  PCacheQueryParams params;
-  ToPCacheQueryParams(params, aOptions);
-
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  unused << mActor->SendMatch(requestId, request.SendAsRequest(), params);
-
-  return promise.forget();
+  return ExecuteOp(args, aRv);
 }
 
 already_AddRefed<Promise>
 Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
                 const CacheQueryOptions& aOptions, ErrorResult& aRv)
 {
   MOZ_ASSERT(mActor);
 
-  nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
-  if (!promise) {
-    return nullptr;
-  }
+  CacheQueryParams params;
+  ToCacheQueryParams(params, aOptions);
 
-  AutoChildRequest request(this);
+  AutoChildOpArgs args(this, CacheMatchAllArgs(void_t(), params));
 
   if (aRequest.WasPassed()) {
     nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
                                                      IgnoreBody, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
 
-    request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
+    args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
   }
 
-  PCacheQueryParams params;
-  ToPCacheQueryParams(params, aOptions);
-
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  unused << mActor->SendMatchAll(requestId, request.SendAsRequestOrVoid(),
-                                 params);
-
-  return promise.forget();
+  return ExecuteOp(args, aRv);
 }
 
 already_AddRefed<Promise>
 Cache::Add(const RequestOrUSVString& aRequest, ErrorResult& aRv)
 {
   MOZ_ASSERT(mActor);
 
   if (!IsValidPutRequestMethod(aRequest, aRv)) {
     return nullptr;
   }
 
-  nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
-  if (!promise) {
-    return nullptr;
-  }
-
   nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  AutoChildRequestList requests(this, 1);
-  requests.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
+  AutoChildOpArgs args(this, CacheAddAllArgs());
+
+  args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  unused << mActor->SendAddAll(requestId, requests.SendAsRequestList());
-
-  return promise.forget();
+  return ExecuteOp(args, aRv);
 }
 
 already_AddRefed<Promise>
 Cache::AddAll(const Sequence<OwningRequestOrUSVString>& aRequests,
               ErrorResult& aRv)
 {
   MOZ_ASSERT(mActor);
 
-  nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
-  if (!promise) {
-    return nullptr;
-  }
-
   // If there is no work to do, then resolve immediately
   if (aRequests.IsEmpty()) {
+    nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
+    if (!promise) {
+      return nullptr;
+    }
+
     promise->MaybeResolve(JS::UndefinedHandleValue);
     return promise.forget();
   }
 
-  AutoChildRequestList requests(this, aRequests.Length());
+  AutoChildOpArgs args(this, CacheAddAllArgs());
 
   for (uint32_t i = 0; i < aRequests.Length(); ++i) {
     if (!IsValidPutRequestMethod(aRequests[i], aRv)) {
       return nullptr;
     }
 
     nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequests[i], ReadBody,
                                                      aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
 
-    requests.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme,
-                 aRv);
+    args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
   }
 
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  unused << mActor->SendAddAll(requestId, requests.SendAsRequestList());
-
-  return promise.forget();
+  return ExecuteOp(args, aRv);
 }
 
 already_AddRefed<Promise>
 Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
            ErrorResult& aRv)
 {
   MOZ_ASSERT(mActor);
 
   if (!IsValidPutRequestMethod(aRequest, aRv)) {
     return nullptr;
   }
 
-  nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
-  if (!promise) {
-    return nullptr;
-  }
-
   nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  AutoChildRequestResponse put(this);
-  put.Add(ir, ReadBody, PassThroughReferrer, TypeErrorOnInvalidScheme, aRv);
+  AutoChildOpArgs args(this, CachePutAllArgs());
+
+  args.Add(ir, ReadBody, PassThroughReferrer, TypeErrorOnInvalidScheme,
+           aResponse, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  put.Add(aResponse, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  unused << mActor->SendPut(requestId, put.SendAsRequestResponse());
-
-  return promise.forget();
+  return ExecuteOp(args, aRv);
 }
 
 already_AddRefed<Promise>
 Cache::Delete(const RequestOrUSVString& aRequest,
               const CacheQueryOptions& aOptions, ErrorResult& aRv)
 {
   MOZ_ASSERT(mActor);
 
-  nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
-  if (!promise) {
-    return nullptr;
-  }
-
   nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  AutoChildRequest request(this);
-  request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
+  CacheQueryParams params;
+  ToCacheQueryParams(params, aOptions);
+
+  AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params));
+
+  args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  PCacheQueryParams params;
-  ToPCacheQueryParams(params, aOptions);
-
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  unused << mActor->SendDelete(requestId, request.SendAsRequest(), params);
-
-  return promise.forget();
+  return ExecuteOp(args, aRv);
 }
 
 already_AddRefed<Promise>
 Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
             const CacheQueryOptions& aOptions, ErrorResult& aRv)
 {
   MOZ_ASSERT(mActor);
 
-  nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
-  if (!promise) {
-    return nullptr;
-  }
+  CacheQueryParams params;
+  ToCacheQueryParams(params, aOptions);
 
-  AutoChildRequest request(this);
+  AutoChildOpArgs args(this, CacheKeysArgs(void_t(), params));
 
   if (aRequest.WasPassed()) {
     nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
                                                      IgnoreBody, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
 
-    request.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
+    args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
   }
 
-  PCacheQueryParams params;
-  ToPCacheQueryParams(params, aOptions);
-
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  unused << mActor->SendKeys(requestId, request.SendAsRequestOrVoid(), params);
-
-  return promise.forget();
+  return ExecuteOp(args, aRv);
 }
 
 // static
 bool
 Cache::PrefEnabled(JSContext* aCx, JSObject* aObj)
 {
   using mozilla::dom::workers::WorkerPrivate;
   using mozilla::dom::workers::GetWorkerPrivateFromContext;
@@ -396,133 +324,16 @@ void
 Cache::DestroyInternal(CacheChild* aActor)
 {
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(mActor == aActor);
   mActor->ClearListener();
   mActor = nullptr;
 }
 
-void
-Cache::RecvMatchResponse(RequestId aRequestId, nsresult aRv,
-                         const PCacheResponseOrVoid& aResponse)
-{
-  // Convert the response immediately if its present.  This ensures that
-  // any stream actors are cleaned up, even if we error out below.
-  nsRefPtr<Response> response;
-  if (aResponse.type() == PCacheResponseOrVoid::TPCacheResponse) {
-    response = ToResponse(aResponse);
-  }
-
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    promise->MaybeReject(aRv);
-    return;
-  }
-
-  if (!response) {
-    promise->MaybeResolve(JS::UndefinedHandleValue);
-    return;
-  }
-
-  promise->MaybeResolve(response);
-}
-
-void
-Cache::RecvMatchAllResponse(RequestId aRequestId, nsresult aRv,
-                            const nsTArray<PCacheResponse>& aResponses)
-{
-  // Convert responses immediately.  This ensures that any stream actors are
-  // cleaned up, even if we error out below.
-  nsAutoTArray<nsRefPtr<Response>, 256> responses;
-  responses.SetCapacity(aResponses.Length());
-
-  for (uint32_t i = 0; i < aResponses.Length(); ++i) {
-    nsRefPtr<Response> response = ToResponse(aResponses[i]);
-    responses.AppendElement(response.forget());
-  }
-
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    promise->MaybeReject(aRv);
-    return;
-  }
-
-  promise->MaybeResolve(responses);
-}
-
-void
-Cache::RecvAddAllResponse(RequestId aRequestId,
-                          const mozilla::ErrorResult& aError)
-{
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (aError.Failed()) {
-    // TODO: Remove this const_cast (bug 1152078).
-    // It is safe for now since this ErrorResult is handed off to us by IPDL
-    // and is thrown into the trash afterwards.
-    promise->MaybeReject(const_cast<ErrorResult&>(aError));
-    return;
-  }
-
-  promise->MaybeResolve(JS::UndefinedHandleValue);
-}
-
-void
-Cache::RecvPutResponse(RequestId aRequestId, nsresult aRv)
-{
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    promise->MaybeReject(aRv);
-    return;
-  }
-
-  promise->MaybeResolve(JS::UndefinedHandleValue);
-}
-
-void
-Cache::RecvDeleteResponse(RequestId aRequestId, nsresult aRv, bool aSuccess)
-{
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    promise->MaybeReject(aRv);
-    return;
-  }
-
-  promise->MaybeResolve(aSuccess);
-}
-
-void
-Cache::RecvKeysResponse(RequestId aRequestId, nsresult aRv,
-                        const nsTArray<PCacheRequest>& aRequests)
-{
-  // Convert requests immediately.  This ensures that any stream actors are
-  // cleaned up, even if we error out below.
-  nsAutoTArray<nsRefPtr<Request>, 256> requests;
-  requests.SetCapacity(aRequests.Length());
-
-  for (uint32_t i = 0; i < aRequests.Length(); ++i) {
-    nsRefPtr<Request> request = ToRequest(aRequests[i]);
-    requests.AppendElement(request.forget());
-  }
-
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    promise->MaybeReject(aRv);
-    return;
-  }
-
-  promise->MaybeResolve(requests);
-}
-
 nsIGlobalObject*
 Cache::GetGlobalObject() const
 {
   return mGlobal;
 }
 
 #ifdef DEBUG
 void
@@ -533,88 +344,37 @@ Cache::AssertOwningThread() const
 #endif
 
 CachePushStreamChild*
 Cache::CreatePushStream(nsIAsyncInputStream* aStream)
 {
   NS_ASSERT_OWNINGTHREAD(Cache);
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(aStream);
-  auto actor = mActor->SendPCachePushStreamConstructor(
-    new CachePushStreamChild(mActor->GetFeature(), aStream));
-  MOZ_ASSERT(actor);
-  return static_cast<CachePushStreamChild*>(actor);
-}
-
-void
-Cache::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
-{
-  // Do nothing.  The Promise will automatically drop the ref to us after
-  // calling the callback.  This is what we want as we only registered in order
-  // to be held alive via the Promise handle.
-}
-
-void
-Cache::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
-{
-  // Do nothing.  The Promise will automatically drop the ref to us after
-  // calling the callback.  This is what we want as we only registered in order
-  // to be held alive via the Promise handle.
+  return mActor->CreatePushStream(aStream);
 }
 
 Cache::~Cache()
 {
-  DisconnectFromActor();
-}
-
-void
-Cache::DisconnectFromActor()
-{
+  NS_ASSERT_OWNINGTHREAD(Cache);
   if (mActor) {
     mActor->StartDestroy();
     // DestroyInternal() is called synchronously by StartDestroy().  So we
     // should have already cleared the mActor.
     MOZ_ASSERT(!mActor);
   }
 }
 
-RequestId
-Cache::AddRequestPromise(Promise* aPromise, ErrorResult& aRv)
+already_AddRefed<Promise>
+Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
 {
-  MOZ_ASSERT(aPromise);
-  MOZ_ASSERT(!mRequestPromises.Contains(aPromise));
-
-  // Register ourself as a promise handler so that the promise will hold us
-  // alive.  This allows the client code to drop the ref to the Cache
-  // object and just keep their promise.  This is fairly common in promise
-  // chaining code.
-  aPromise->AppendNativeHandler(this);
-
-  mRequestPromises.AppendElement(aPromise);
-
-  // (Ab)use the promise pointer as our request ID.  This is a fast, thread-safe
-  // way to get a unique ID for the promise to be resolved later.
-  return reinterpret_cast<RequestId>(aPromise);
-}
+  nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
+  if (!promise) {
+    return nullptr;
+  }
 
-already_AddRefed<Promise>
-Cache::RemoveRequestPromise(RequestId aRequestId)
-{
-  MOZ_ASSERT(aRequestId != INVALID_REQUEST_ID);
-
-  for (uint32_t i = 0; i < mRequestPromises.Length(); ++i) {
-    nsRefPtr<Promise>& promise = mRequestPromises.ElementAt(i);
-    // To be safe, only cast promise pointers to our integer RequestId
-    // type and never cast an integer to a pointer.
-    if (aRequestId == reinterpret_cast<RequestId>(promise.get())) {
-      nsRefPtr<Promise> ref;
-      ref.swap(promise);
-      mRequestPromises.RemoveElementAt(i);
-      return ref.forget();
-    }
-  }
-  MOZ_ASSERT_UNREACHABLE("Received response without a matching promise!");
-  return nullptr;
+  mActor->ExecuteOp(mGlobal, promise, aOpArgs.SendAsOpArgs());
+  return promise.forget();
 }
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/Cache.h
+++ b/dom/cache/Cache.h
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef mozilla_dom_cache_Cache_h
 #define mozilla_dom_cache_Cache_h
 
-#include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/cache/Types.h"
 #include "mozilla/dom/cache/TypeUtils.h"
 #include "nsCOMPtr.h"
 #include "nsISupportsImpl.h"
 #include "nsString.h"
 #include "nsWrapperCache.h"
 
 class nsIGlobalObject;
@@ -28,22 +27,20 @@ class Promise;
 struct CacheQueryOptions;
 class RequestOrUSVString;
 class Response;
 template<typename T> class Optional;
 template<typename T> class Sequence;
 
 namespace cache {
 
+class AutoChildOpArgs;
 class CacheChild;
-class PCacheRequest;
-class PCacheResponse;
-class PCacheResponseOrVoid;
 
-class Cache final : public PromiseNativeHandler
+class Cache final : public nsISupports
                   , public nsWrapperCache
                   , public TypeUtils
 {
 public:
   Cache(nsIGlobalObject* aGlobal, CacheChild* aActor);
 
   // webidl interface methods
   already_AddRefed<Promise>
@@ -71,61 +68,38 @@ public:
   static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
 
   nsISupports* GetParentObject() const;
   virtual JSObject* WrapObject(JSContext* aContext, JS::Handle<JSObject*> aGivenProto) override;
 
   // Called when CacheChild actor is being destroyed
   void DestroyInternal(CacheChild* aActor);
 
-  // methods forwarded from CacheChild
-  void RecvMatchResponse(RequestId aRequestId, nsresult aRv,
-                         const PCacheResponseOrVoid& aResponse);
-  void RecvMatchAllResponse(RequestId aRequestId, nsresult aRv,
-                            const nsTArray<PCacheResponse>& aResponses);
-  void RecvAddAllResponse(RequestId aRequestId,
-                          const mozilla::ErrorResult& aError);
-  void RecvPutResponse(RequestId aRequestId, nsresult aRv);
-
-  void RecvDeleteResponse(RequestId aRequestId, nsresult aRv,
-                          bool aSuccess);
-  void RecvKeysResponse(RequestId aRequestId, nsresult aRv,
-                        const nsTArray<PCacheRequest>& aRequests);
-
   // TypeUtils methods
   virtual nsIGlobalObject*
   GetGlobalObject() const override;
 
 #ifdef DEBUG
   virtual void AssertOwningThread() const override;
 #endif
 
   virtual CachePushStreamChild*
   CreatePushStream(nsIAsyncInputStream* aStream) override;
 
-  // PromiseNativeHandler methods
-  virtual void
-  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
-
-  virtual void
-  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
-
 private:
   ~Cache();
 
   // Called when we're destroyed or CCed.
   void DisconnectFromActor();
 
-  // TODO: Replace with actor-per-request model during refactor (bug 1110485)
-  RequestId AddRequestPromise(Promise* aPromise, ErrorResult& aRv);
-  already_AddRefed<Promise> RemoveRequestPromise(RequestId aRequestId);
+  already_AddRefed<Promise>
+  ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv);
 
   nsCOMPtr<nsIGlobalObject> mGlobal;
   CacheChild* mActor;
-  nsTArray<nsRefPtr<Promise>> mRequestPromises;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Cache)
 };
 
 } // namespace cache
 } // namespace dom
--- a/dom/cache/CacheChild.cpp
+++ b/dom/cache/CacheChild.cpp
@@ -4,18 +4,18 @@
  * 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/. */
 
 #include "mozilla/dom/cache/CacheChild.h"
 
 #include "mozilla/unused.h"
 #include "mozilla/dom/cache/ActorUtils.h"
 #include "mozilla/dom/cache/Cache.h"
-#include "mozilla/dom/cache/PCachePushStreamChild.h"
-#include "mozilla/dom/cache/StreamUtils.h"
+#include "mozilla/dom/cache/CacheOpChild.h"
+#include "mozilla/dom/cache/CachePushStreamChild.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 // Declared in ActorUtils.h
 PCacheChild*
 AllocPCacheChild()
@@ -27,25 +27,27 @@ AllocPCacheChild()
 void
 DeallocPCacheChild(PCacheChild* aActor)
 {
   delete aActor;
 }
 
 CacheChild::CacheChild()
   : mListener(nullptr)
+  , mNumChildActors(0)
 {
   MOZ_COUNT_CTOR(cache::CacheChild);
 }
 
 CacheChild::~CacheChild()
 {
   MOZ_COUNT_DTOR(cache::CacheChild);
   NS_ASSERT_OWNINGTHREAD(CacheChild);
   MOZ_ASSERT(!mListener);
+  MOZ_ASSERT(!mNumChildActors);
 }
 
 void
 CacheChild::SetListener(Cache* aListener)
 {
   NS_ASSERT_OWNINGTHREAD(CacheChild);
   MOZ_ASSERT(!mListener);
   mListener = aListener;
@@ -56,32 +58,59 @@ void
 CacheChild::ClearListener()
 {
   NS_ASSERT_OWNINGTHREAD(CacheChild);
   MOZ_ASSERT(mListener);
   mListener = nullptr;
 }
 
 void
+CacheChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
+                      const CacheOpArgs& aArgs)
+{
+  mNumChildActors += 1;
+  MOZ_ALWAYS_TRUE(SendPCacheOpConstructor(
+    new CacheOpChild(GetFeature(), aGlobal, aPromise), aArgs));
+}
+
+CachePushStreamChild*
+CacheChild::CreatePushStream(nsIAsyncInputStream* aStream)
+{
+  mNumChildActors += 1;
+  auto actor = SendPCachePushStreamConstructor(
+    new CachePushStreamChild(GetFeature(), aStream));
+  MOZ_ASSERT(actor);
+  return static_cast<CachePushStreamChild*>(actor);
+}
+
+void
 CacheChild::StartDestroy()
 {
   nsRefPtr<Cache> listener = mListener;
 
   // StartDestroy() can get called from either Cache or the Feature.
   // Theoretically we can get double called if the right race happens.  Handle
   // that by just ignoring the second StartDestroy() call.
   if (!listener) {
     return;
   }
 
   listener->DestroyInternal(this);
 
   // Cache listener should call ClearListener() in DestroyInternal()
   MOZ_ASSERT(!mListener);
 
+  // If we have outstanding child actors, then don't destroy ourself yet.
+  // The child actors should be short lived and we should allow them to complete
+  // if possible.  SendTeardown() will be called when the count drops to zero
+  // in NoteDeletedActor().
+  if (mNumChildActors) {
+    return;
+  }
+
   // Start actor destruction from parent process
   unused << SendTeardown();
 }
 
 void
 CacheChild::ActorDestroy(ActorDestroyReason aReason)
 {
   NS_ASSERT_OWNINGTHREAD(CacheChild);
@@ -90,114 +119,50 @@ CacheChild::ActorDestroy(ActorDestroyRea
     listener->DestroyInternal(this);
     // Cache listener should call ClearListener() in DestroyInternal()
     MOZ_ASSERT(!mListener);
   }
 
   RemoveFeature();
 }
 
+PCacheOpChild*
+CacheChild::AllocPCacheOpChild(const CacheOpArgs& aOpArgs)
+{
+  MOZ_CRASH("CacheOpChild should be manually constructed.");
+  return nullptr;
+}
+
+bool
+CacheChild::DeallocPCacheOpChild(PCacheOpChild* aActor)
+{
+  delete aActor;
+  NoteDeletedActor();
+  return true;
+}
+
 PCachePushStreamChild*
 CacheChild::AllocPCachePushStreamChild()
 {
   MOZ_CRASH("CachePushStreamChild should be manually constructed.");
   return nullptr;
 }
 
 bool
 CacheChild::DeallocPCachePushStreamChild(PCachePushStreamChild* aActor)
 {
   delete aActor;
-  return true;
-}
-
-bool
-CacheChild::RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
-                              const PCacheResponseOrVoid& aResponse)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheChild);
-
-  AddFeatureToStreamChild(aResponse, GetFeature());
-
-  nsRefPtr<Cache> listener = mListener;
-  if (!listener) {
-    StartDestroyStreamChild(aResponse);
-    return true;
-  }
-
-  listener->RecvMatchResponse(requestId, aRv, aResponse);
-  return true;
-}
-
-bool
-CacheChild::RecvMatchAllResponse(const RequestId& requestId, const nsresult& aRv,
-                                 nsTArray<PCacheResponse>&& aResponses)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheChild);
-
-  AddFeatureToStreamChild(aResponses, GetFeature());
-
-  nsRefPtr<Cache> listener = mListener;
-  if (!listener) {
-    StartDestroyStreamChild(aResponses);
-    return true;
-  }
-
-  listener->RecvMatchAllResponse(requestId, aRv, aResponses);
+  NoteDeletedActor();
   return true;
 }
 
-bool
-CacheChild::RecvAddAllResponse(const RequestId& requestId,
-                               const mozilla::ErrorResult& aError)
+void
+CacheChild::NoteDeletedActor()
 {
-  NS_ASSERT_OWNINGTHREAD(CacheChild);
-  nsRefPtr<Cache> listener = mListener;
-  if (listener) {
-    listener->RecvAddAllResponse(requestId, aError);
-  }
-  return true;
-}
-
-bool
-CacheChild::RecvPutResponse(const RequestId& aRequestId, const nsresult& aRv)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheChild);
-  nsRefPtr<Cache> listener = mListener;
-  if (listener) {
-    listener->RecvPutResponse(aRequestId, aRv);
+  mNumChildActors -= 1;
+  if (!mNumChildActors && !mListener) {
+    unused << SendTeardown();
   }
-  return true;
-}
-
-bool
-CacheChild::RecvDeleteResponse(const RequestId& requestId, const nsresult& aRv,
-                               const bool& result)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheChild);
-  nsRefPtr<Cache> listener = mListener;
-  if (listener) {
-    listener->RecvDeleteResponse(requestId, aRv, result);
-  }
-  return true;
-}
-
-bool
-CacheChild::RecvKeysResponse(const RequestId& requestId, const nsresult& aRv,
-                             nsTArray<PCacheRequest>&& aRequests)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheChild);
-
-  AddFeatureToStreamChild(aRequests, GetFeature());
-
-  nsRefPtr<Cache> listener = mListener;
-  if (!listener) {
-    StartDestroyStreamChild(aRequests);
-    return true;
-  }
-
-  listener->RecvKeysResponse(requestId, aRv, aRequests);
-  return true;
 }
 
 } // namespace cache
 } // namespace dom
 } // namesapce mozilla
--- a/dom/cache/CacheChild.h
+++ b/dom/cache/CacheChild.h
@@ -5,76 +5,83 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_cache_CacheChild_h
 #define mozilla_dom_cache_CacheChild_h
 
 #include "mozilla/dom/cache/ActorChild.h"
 #include "mozilla/dom/cache/PCacheChild.h"
 
+class nsIAsyncInputStream;
+class nsIGlobalObject;
+
 namespace mozilla {
 namespace dom {
+
+class Promise;
+
 namespace cache {
 
 class Cache;
+class CacheOpArgs;
+class CachePushStreamChild;
 
 class CacheChild final : public PCacheChild
                        , public ActorChild
 {
 public:
   CacheChild();
   ~CacheChild();
 
   void SetListener(Cache* aListener);
 
   // Must be called by the associated Cache listener in its ActorDestroy()
   // method.  Also, Cache must Send__delete__() the actor in its destructor to
   // trigger ActorDestroy() if it has not been called yet.
   void ClearListener();
 
+  void
+  ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
+            const CacheOpArgs& aArgs);
+
+  CachePushStreamChild*
+  CreatePushStream(nsIAsyncInputStream* aStream);
+
   // ActorChild methods
 
   // Synchronously call ActorDestroy on our Cache listener and then start the
   // actor destruction asynchronously from the parent-side.
   virtual void StartDestroy() override;
 
 private:
   // PCacheChild methods
   virtual void
   ActorDestroy(ActorDestroyReason aReason) override;
 
+  virtual PCacheOpChild*
+  AllocPCacheOpChild(const CacheOpArgs& aOpArgs) override;
+
+  virtual bool
+  DeallocPCacheOpChild(PCacheOpChild* aActor) override;
+
   virtual PCachePushStreamChild*
   AllocPCachePushStreamChild() override;
 
   virtual bool
   DeallocPCachePushStreamChild(PCachePushStreamChild* aActor) override;
 
-  virtual bool
-  RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
-                    const PCacheResponseOrVoid& aResponse) override;
-  virtual bool
-  RecvMatchAllResponse(const RequestId& requestId, const nsresult& aRv,
-                       nsTArray<PCacheResponse>&& responses) override;
-  virtual bool
-  RecvAddAllResponse(const RequestId& requestId,
-                     const mozilla::ErrorResult& aError) override;
-  virtual bool
-  RecvPutResponse(const RequestId& aRequestId,
-                  const nsresult& aRv) override;
-  virtual bool
-  RecvDeleteResponse(const RequestId& requestId, const nsresult& aRv,
-                     const bool& result) override;
-  virtual bool
-  RecvKeysResponse(const RequestId& requestId, const nsresult& aRv,
-                   nsTArray<PCacheRequest>&& requests) override;
+  // utility methods
+  void
+  NoteDeletedActor();
 
   // Use a weak ref so actor does not hold DOM object alive past content use.
   // The Cache object must call ClearListener() to null this before its
   // destroyed.
   Cache* MOZ_NON_OWNING_REF mListener;
+  uint32_t mNumChildActors;
 
   NS_DECL_OWNINGTHREAD
 };
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
 
deleted file mode 100644
--- a/dom/cache/CacheInitData.ipdlh
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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/. */
-
-include PBackgroundSharedTypes;
-
-using mozilla::dom::cache::Namespace from "mozilla/dom/cache/Types.h";
-
-namespace mozilla {
-namespace dom {
-namespace cache {
-
-// Data needed to initialize a CacheStorage or Cache backend.  Don't put
-// this with the other types in PCacheTypes.ipdlh since we want to import
-// it into PBackground.ipdl.
-struct CacheInitData
-{
-  Namespace namespaceEnum;
-  PrincipalInfo principalInfo;
-};
-
-} // namespace cache
-} // namespace dom
-} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/cache/CacheOpChild.cpp
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "mozilla/dom/cache/CacheOpChild.h"
+
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/Request.h"
+#include "mozilla/dom/Response.h"
+#include "mozilla/dom/cache/Cache.h"
+#include "mozilla/dom/cache/CacheChild.h"
+#include "mozilla/dom/cache/CacheStreamControlChild.h"
+
+namespace mozilla {
+namespace dom {
+namespace cache {
+
+namespace {
+
+void
+AddFeatureToStreamChild(const CacheReadStream& aReadStream, Feature* aFeature)
+{
+  MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
+  CacheStreamControlChild* cacheControl =
+    static_cast<CacheStreamControlChild*>(aReadStream.controlChild());
+  if (cacheControl) {
+    cacheControl->SetFeature(aFeature);
+  }
+}
+
+void
+AddFeatureToStreamChild(const CacheResponse& aResponse, Feature* aFeature)
+{
+  MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
+
+  if (aResponse.body().type() == CacheReadStreamOrVoid::Tvoid_t) {
+    return;
+  }
+
+  AddFeatureToStreamChild(aResponse.body().get_CacheReadStream(), aFeature);
+}
+
+void
+AddFeatureToStreamChild(const CacheRequest& aRequest, Feature* aFeature)
+{
+  MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
+
+  if (aRequest.body().type() == CacheReadStreamOrVoid::Tvoid_t) {
+    return;
+  }
+
+  AddFeatureToStreamChild(aRequest.body().get_CacheReadStream(), aFeature);
+}
+
+} // anonymous namespace
+
+CacheOpChild::CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal,
+                           Promise* aPromise)
+  : mGlobal(aGlobal)
+  , mPromise(aPromise)
+{
+  MOZ_ASSERT(mGlobal);
+  MOZ_ASSERT(mPromise);
+
+  MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
+  SetFeature(aFeature);
+}
+
+CacheOpChild::~CacheOpChild()
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpChild);
+  MOZ_ASSERT(!mPromise);
+}
+
+void
+CacheOpChild::ActorDestroy(ActorDestroyReason aReason)
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpChild);
+
+  // If the actor was terminated for some unknown reason, then indicate the
+  // operation is dead.
+  if (mPromise) {
+    mPromise->MaybeReject(NS_ERROR_FAILURE);
+    mPromise = nullptr;
+  }
+
+  RemoveFeature();
+}
+
+bool
+CacheOpChild::Recv__delete__(const ErrorResult& aRv,
+                             const CacheOpResult& aResult)
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpChild);
+
+  if (aRv.Failed()) {
+    MOZ_ASSERT(aResult.type() == CacheOpResult::Tvoid_t);
+    // TODO: Remove this const_cast (bug 1152078).
+    // It is safe for now since this ErrorResult is handed off to us by IPDL
+    // and is thrown into the trash afterwards.
+    mPromise->MaybeReject(const_cast<ErrorResult&>(aRv));
+    mPromise = nullptr;
+    return true;
+  }
+
+  switch (aResult.type()) {
+    case CacheOpResult::TCacheMatchResult:
+    {
+      HandleResponse(aResult.get_CacheMatchResult().responseOrVoid());
+      break;
+    }
+    case CacheOpResult::TCacheMatchAllResult:
+    {
+      HandleResponseList(aResult.get_CacheMatchAllResult().responseList());
+      break;
+    }
+    case CacheOpResult::TCacheAddAllResult:
+    case CacheOpResult::TCachePutAllResult:
+    {
+      mPromise->MaybeResolve(JS::UndefinedHandleValue);
+      break;
+    }
+    case CacheOpResult::TCacheDeleteResult:
+    {
+      mPromise->MaybeResolve(aResult.get_CacheDeleteResult().success());
+      break;
+    }
+    case CacheOpResult::TCacheKeysResult:
+    {
+      HandleRequestList(aResult.get_CacheKeysResult().requestList());
+      break;
+    }
+    case CacheOpResult::TStorageMatchResult:
+    {
+      HandleResponse(aResult.get_StorageMatchResult().responseOrVoid());
+      break;
+    }
+    case CacheOpResult::TStorageHasResult:
+    {
+      mPromise->MaybeResolve(aResult.get_StorageHasResult().success());
+      break;
+    }
+    case CacheOpResult::TStorageOpenResult:
+    {
+      auto actor = static_cast<CacheChild*>(
+        aResult.get_StorageOpenResult().actorChild());
+      actor->SetFeature(GetFeature());
+      nsRefPtr<Cache> cache = new Cache(mGlobal, actor);
+      mPromise->MaybeResolve(cache);
+      break;
+    }
+    case CacheOpResult::TStorageDeleteResult:
+    {
+      mPromise->MaybeResolve(aResult.get_StorageDeleteResult().success());
+      break;
+    }
+    case CacheOpResult::TStorageKeysResult:
+    {
+      mPromise->MaybeResolve(aResult.get_StorageKeysResult().keyList());
+      break;
+    }
+    default:
+      MOZ_CRASH("Unknown Cache op result type!");
+  }
+
+  mPromise = nullptr;
+
+  return true;
+}
+
+void
+CacheOpChild::StartDestroy()
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpChild);
+
+  // Do not cancel on-going operations when Feature calls this.  Instead, keep
+  // the Worker alive until we are done.
+}
+
+nsIGlobalObject*
+CacheOpChild::GetGlobalObject() const
+{
+  return mGlobal;
+}
+
+#ifdef DEBUG
+void
+CacheOpChild::AssertOwningThread() const
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpChild);
+}
+#endif
+
+CachePushStreamChild*
+CacheOpChild::CreatePushStream(nsIAsyncInputStream* aStream)
+{
+  MOZ_CRASH("CacheOpChild should never create a push stream actor!");
+}
+
+void
+CacheOpChild::HandleResponse(const CacheResponseOrVoid& aResponseOrVoid)
+{
+  if (aResponseOrVoid.type() == CacheResponseOrVoid::Tvoid_t) {
+    mPromise->MaybeResolve(JS::UndefinedHandleValue);
+    return;
+  }
+
+  const CacheResponse& cacheResponse = aResponseOrVoid.get_CacheResponse();
+
+  AddFeatureToStreamChild(cacheResponse, GetFeature());
+  nsRefPtr<Response> response = ToResponse(cacheResponse);
+
+  mPromise->MaybeResolve(response);
+}
+
+void
+CacheOpChild::HandleResponseList(const nsTArray<CacheResponse>& aResponseList)
+{
+  nsAutoTArray<nsRefPtr<Response>, 256> responses;
+  responses.SetCapacity(aResponseList.Length());
+
+  for (uint32_t i = 0; i < aResponseList.Length(); ++i) {
+    AddFeatureToStreamChild(aResponseList[i], GetFeature());
+    responses.AppendElement(ToResponse(aResponseList[i]));
+  }
+
+  mPromise->MaybeResolve(responses);
+}
+
+void
+CacheOpChild::HandleRequestList(const nsTArray<CacheRequest>& aRequestList)
+{
+  nsAutoTArray<nsRefPtr<Request>, 256> requests;
+  requests.SetCapacity(aRequestList.Length());
+
+  for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
+    AddFeatureToStreamChild(aRequestList[i], GetFeature());
+    requests.AppendElement(ToRequest(aRequestList[i]));
+  }
+
+  mPromise->MaybeResolve(requests);
+}
+
+} // namespace cache
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/cache/CacheOpChild.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_dom_cache_CacheOpChild_h
+#define mozilla_dom_cache_CacheOpChild_h
+
+#include "mozilla/dom/cache/ActorChild.h"
+#include "mozilla/dom/cache/PCacheOpChild.h"
+#include "mozilla/dom/cache/TypeUtils.h"
+#include "nsRefPtr.h"
+
+class nsIGlobalObject;
+
+namespace mozilla {
+namespace dom {
+
+class Promise;
+
+namespace cache {
+
+class CacheOpChild final : public PCacheOpChild
+                         , public ActorChild
+                         , public TypeUtils
+{
+  friend class CacheChild;
+  friend class CacheStorageChild;
+
+private:
+  // This class must be constructed by CacheChild or CacheStorageChild using
+  // their ExecuteOp() factory method.
+  CacheOpChild(Feature* aFeature, nsIGlobalObject* aGlobal, Promise* aPromise);
+  ~CacheOpChild();
+
+  // PCacheOpChild methods
+  virtual void
+  ActorDestroy(ActorDestroyReason aReason) override;
+
+  virtual bool
+  Recv__delete__(const ErrorResult& aRv, const CacheOpResult& aResult) override;
+
+  // ActorChild methods
+  virtual void
+  StartDestroy() override;
+
+  // TypeUtils methods
+  virtual nsIGlobalObject*
+  GetGlobalObject() const override;
+
+#ifdef DEBUG
+  virtual void
+  AssertOwningThread() const override;
+#endif
+
+  virtual CachePushStreamChild*
+  CreatePushStream(nsIAsyncInputStream* aStream) override;
+
+  // Utility methods
+  void
+  HandleResponse(const CacheResponseOrVoid& aResponseOrVoid);
+
+  void
+  HandleResponseList(const nsTArray<CacheResponse>& aResponseList);
+
+  void
+  HandleRequestList(const nsTArray<CacheRequest>& aRequestList);
+
+  nsCOMPtr<nsIGlobalObject> mGlobal;
+  nsRefPtr<Promise> mPromise;
+
+  NS_DECL_OWNINGTHREAD
+};
+
+} // namespace cache
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_cache_CacheOpChild_h
new file mode 100644
--- /dev/null
+++ b/dom/cache/CacheOpParent.cpp
@@ -0,0 +1,287 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "mozilla/dom/cache/CacheOpParent.h"
+
+#include "mozilla/unused.h"
+#include "mozilla/dom/cache/AutoUtils.h"
+#include "mozilla/dom/cache/CachePushStreamParent.h"
+#include "mozilla/dom/cache/ReadStream.h"
+#include "mozilla/dom/cache/SavedTypes.h"
+#include "mozilla/ipc/FileDescriptorSetParent.h"
+#include "mozilla/ipc/InputStreamUtils.h"
+
+namespace mozilla {
+namespace dom {
+namespace cache {
+
+using mozilla::ipc::FileDescriptorSetParent;
+using mozilla::ipc::PBackgroundParent;
+
+CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager, CacheId aCacheId,
+                             const CacheOpArgs& aOpArgs)
+  : mIpcManager(aIpcManager)
+  , mCacheId(aCacheId)
+  , mNamespace(INVALID_NAMESPACE)
+  , mOpArgs(aOpArgs)
+{
+  MOZ_ASSERT(mIpcManager);
+}
+
+CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager,
+                             Namespace aNamespace, const CacheOpArgs& aOpArgs)
+  : mIpcManager(aIpcManager)
+  , mCacheId(INVALID_CACHE_ID)
+  , mNamespace(aNamespace)
+  , mOpArgs(aOpArgs)
+{
+  MOZ_ASSERT(mIpcManager);
+}
+
+CacheOpParent::~CacheOpParent()
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpParent);
+}
+
+void
+CacheOpParent::Execute(ManagerId* aManagerId)
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpParent);
+  MOZ_ASSERT(!mManager);
+  MOZ_ASSERT(!mVerifier);
+
+  nsRefPtr<Manager> manager;
+  nsresult rv = Manager::GetOrCreate(aManagerId, getter_AddRefs(manager));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    unused << Send__delete__(this, ErrorResult(rv), void_t());
+    return;
+  }
+
+  Execute(manager);
+}
+
+void
+CacheOpParent::Execute(Manager* aManager)
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpParent);
+  MOZ_ASSERT(!mManager);
+  MOZ_ASSERT(!mVerifier);
+
+  mManager = aManager;
+
+  // Handle add/addAll op with a FetchPut object
+  if (mOpArgs.type() == CacheOpArgs::TCacheAddAllArgs) {
+    MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
+
+    const CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
+    const nsTArray<CacheRequest>& list = args.requestList();
+
+    nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreamList;
+    for (uint32_t i = 0; i < list.Length(); ++i) {
+      requestStreamList.AppendElement(DeserializeCacheStream(list[i].body()));
+    }
+
+    nsRefPtr<FetchPut> fetchPut;
+    nsresult rv = FetchPut::Create(this, mManager, mCacheId, list,
+                                   requestStreamList, getter_AddRefs(fetchPut));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      OnOpComplete(ErrorResult(rv), CacheAddAllResult());
+      return;
+    }
+
+    mFetchPutList.AppendElement(fetchPut.forget());
+    return;
+  }
+
+  // Handle put op
+  if (mOpArgs.type() == CacheOpArgs::TCachePutAllArgs) {
+    MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
+
+    const CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
+    const nsTArray<CacheRequestResponse>& list = args.requestResponseList();
+
+    nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreamList;
+    nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> responseStreamList;
+
+    for (uint32_t i = 0; i < list.Length(); ++i) {
+      requestStreamList.AppendElement(
+        DeserializeCacheStream(list[i].request().body()));
+      responseStreamList.AppendElement(
+        DeserializeCacheStream(list[i].response().body()));
+    }
+
+    mManager->ExecutePutAll(this, mCacheId, args.requestResponseList(),
+                            requestStreamList, responseStreamList);
+    return;
+  }
+
+  // Handle all other cache ops
+  if (mCacheId != INVALID_CACHE_ID) {
+    MOZ_ASSERT(mNamespace == INVALID_NAMESPACE);
+    mManager->ExecuteCacheOp(this, mCacheId, mOpArgs);
+    return;
+  }
+
+  // Handle all storage ops
+  MOZ_ASSERT(mNamespace != INVALID_NAMESPACE);
+  mManager->ExecuteStorageOp(this, mNamespace, mOpArgs);
+}
+
+void
+CacheOpParent::WaitForVerification(PrincipalVerifier* aVerifier)
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpParent);
+  MOZ_ASSERT(!mManager);
+  MOZ_ASSERT(!mVerifier);
+
+  mVerifier = aVerifier;
+  mVerifier->AddListener(this);
+}
+
+void
+CacheOpParent::ActorDestroy(ActorDestroyReason aReason)
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpParent);
+
+  if (mVerifier) {
+    mVerifier->RemoveListener(this);
+    mVerifier = nullptr;
+  }
+
+  for (uint32_t i = 0; i < mFetchPutList.Length(); ++i) {
+    mFetchPutList[i]->ClearListener();
+  }
+  mFetchPutList.Clear();
+
+  if (mManager) {
+    mManager->RemoveListener(this);
+    mManager = nullptr;
+  }
+
+  mIpcManager = nullptr;
+}
+
+void
+CacheOpParent::OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId)
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpParent);
+
+  mVerifier->RemoveListener(this);
+  mVerifier = nullptr;
+
+  if (NS_WARN_IF(NS_FAILED(aRv))) {
+    unused << Send__delete__(this, ErrorResult(aRv), void_t());
+    return;
+  }
+
+  Execute(aManagerId);
+}
+
+void
+CacheOpParent::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
+                            CacheId aOpenedCacheId,
+                            const nsTArray<SavedResponse>& aSavedResponseList,
+                            const nsTArray<SavedRequest>& aSavedRequestList,
+                            StreamList* aStreamList)
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpParent);
+  MOZ_ASSERT(mIpcManager);
+  MOZ_ASSERT(mManager);
+
+  // Never send an op-specific result if we have an error.  Instead, send
+  // void_t() to ensure that we don't leak actors on the child side.
+  if (aRv.Failed()) {
+    unused << Send__delete__(this, aRv, void_t());
+    aRv.ClearMessage(); // This may contain a TypeError.
+    return;
+  }
+
+  // The result must contain the appropriate type at this point.  It may
+  // or may not contain the additional result data yet.  For types that
+  // do not need special processing, it should already be set.  If the
+  // result requires actor-specific operations, then we do that below.
+  // If the type and data types don't match, then we will trigger an
+  // assertion in AutoParentOpResult::Add().
+  AutoParentOpResult result(mIpcManager, aResult);
+
+  if (aOpenedCacheId != INVALID_CACHE_ID) {
+    result.Add(aOpenedCacheId, mManager);
+  }
+
+  for (uint32_t i = 0; i < aSavedResponseList.Length(); ++i) {
+    result.Add(aSavedResponseList[i], aStreamList);
+  }
+
+  for (uint32_t i = 0; i < aSavedRequestList.Length(); ++i) {
+    result.Add(aSavedRequestList[i], aStreamList);
+  }
+
+  unused << Send__delete__(this, aRv, result.SendAsOpResult());
+}
+
+void
+CacheOpParent::OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv)
+{
+  NS_ASSERT_OWNINGTHREAD(CacheOpParent);
+  MOZ_ASSERT(aFetchPut);
+
+  aFetchPut->ClearListener();
+  MOZ_ALWAYS_TRUE(mFetchPutList.RemoveElement(aFetchPut));
+
+  OnOpComplete(Move(aRv), CacheAddAllResult());
+}
+
+already_AddRefed<nsIInputStream>
+CacheOpParent::DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid)
+{
+  if (aStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIInputStream> stream;
+  const CacheReadStream& readStream = aStreamOrVoid.get_CacheReadStream();
+
+  // Option 1: A push stream actor was sent for nsPipe data
+  if (readStream.pushStreamParent()) {
+    MOZ_ASSERT(!readStream.controlParent());
+    CachePushStreamParent* pushStream =
+      static_cast<CachePushStreamParent*>(readStream.pushStreamParent());
+    stream = pushStream->TakeReader();
+    MOZ_ASSERT(stream);
+    return stream.forget();
+  }
+
+  // Option 2: One of our own ReadStreams was passed back to us with a stream
+  //           control actor.
+  stream = ReadStream::Create(readStream);
+  if (stream) {
+    return stream.forget();
+  }
+
+  // Option 3: A stream was serialized using normal methods.
+  nsAutoTArray<FileDescriptor, 4> fds;
+  if (readStream.fds().type() ==
+      OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
+
+    FileDescriptorSetParent* fdSetActor =
+      static_cast<FileDescriptorSetParent*>(readStream.fds().get_PFileDescriptorSetParent());
+    MOZ_ASSERT(fdSetActor);
+
+    fdSetActor->ForgetFileDescriptors(fds);
+    MOZ_ASSERT(!fds.IsEmpty());
+
+    if (!fdSetActor->Send__delete__(fdSetActor)) {
+      // child process is gone, warn and allow actor to clean up normally
+      NS_WARNING("Cache failed to delete fd set actor.");
+    }
+  }
+
+  return DeserializeInputStream(readStream.params(), fds);
+}
+
+} // namespace cache
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/cache/CacheOpParent.h
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_dom_cache_CacheOpParent_h
+#define mozilla_dom_cache_CacheOpParent_h
+
+#include "mozilla/dom/cache/FetchPut.h"
+#include "mozilla/dom/cache/Manager.h"
+#include "mozilla/dom/cache/PCacheOpParent.h"
+#include "mozilla/dom/cache/PrincipalVerifier.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace ipc {
+class PBackgroundParent;
+}
+namespace dom {
+namespace cache {
+
+class CacheOpParent final : public PCacheOpParent
+                          , public PrincipalVerifier::Listener
+                          , public Manager::Listener
+                          , public FetchPut::Listener
+{
+  // to allow use of convenience overrides
+  using Manager::Listener::OnOpComplete;
+
+public:
+  CacheOpParent(mozilla::ipc::PBackgroundParent* aIpcManager, CacheId aCacheId,
+                const CacheOpArgs& aOpArgs);
+  CacheOpParent(mozilla::ipc::PBackgroundParent* aIpcManager,
+                Namespace aNamespace, const CacheOpArgs& aOpArgs);
+  ~CacheOpParent();
+
+  void
+  Execute(ManagerId* aManagerId);
+
+  void
+  Execute(Manager* aManager);
+
+  void
+  WaitForVerification(PrincipalVerifier* aVerifier);
+
+private:
+  // PCacheOpParent methods
+  virtual void
+  ActorDestroy(ActorDestroyReason aReason) override;
+
+  // PrincipalVerifier::Listener methods
+  virtual void
+  OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId) override;
+
+  // Manager::Listener methods
+  virtual void
+  OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
+               CacheId aOpenedCacheId,
+               const nsTArray<SavedResponse>& aSavedResponseList,
+               const nsTArray<SavedRequest>& aSavedRequestList,
+               StreamList* aStreamList) override;
+
+  // FetchPut::Listener methods
+  virtual void
+  OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv) override;
+
+  // utility methods
+  already_AddRefed<nsIInputStream>
+  DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid);
+
+  mozilla::ipc::PBackgroundParent* mIpcManager;
+  const CacheId mCacheId;
+  const Namespace mNamespace;
+  const CacheOpArgs mOpArgs;
+  nsRefPtr<Manager> mManager;
+  nsRefPtr<PrincipalVerifier> mVerifier;
+  nsTArray<nsRefPtr<FetchPut>> mFetchPutList;
+
+  NS_DECL_OWNINGTHREAD
+};
+
+} // namespace cache
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_cache_CacheOpParent_h
--- a/dom/cache/CacheParent.cpp
+++ b/dom/cache/CacheParent.cpp
@@ -1,37 +1,24 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "mozilla/dom/cache/CacheParent.h"
 
-#include "mozilla/DebugOnly.h"
-#include "mozilla/dom/cache/AutoUtils.h"
+#include "mozilla/dom/cache/CacheOpParent.h"
 #include "mozilla/dom/cache/CachePushStreamParent.h"
-#include "mozilla/dom/cache/CacheStreamControlParent.h"
-#include "mozilla/dom/cache/ReadStream.h"
-#include "mozilla/dom/cache/SavedTypes.h"
-#include "mozilla/dom/cache/StreamList.h"
-#include "mozilla/ipc/InputStreamUtils.h"
-#include "mozilla/ipc/PBackgroundParent.h"
-#include "mozilla/ipc/FileDescriptorSetParent.h"
-#include "mozilla/ipc/PFileDescriptorSetParent.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
-using mozilla::dom::ErrNum;
-using mozilla::ipc::FileDescriptorSetParent;
-using mozilla::ipc::PFileDescriptorSetParent;
-
 // Declared in ActorUtils.h
 void
 DeallocPCacheParent(PCacheParent* aActor)
 {
   delete aActor;
 }
 
 CacheParent::CacheParent(cache::Manager* aManager, CacheId aCacheId)
@@ -42,32 +29,58 @@ CacheParent::CacheParent(cache::Manager*
   MOZ_ASSERT(mManager);
   mManager->AddRefCacheId(mCacheId);
 }
 
 CacheParent::~CacheParent()
 {
   MOZ_COUNT_DTOR(cache::CacheParent);
   MOZ_ASSERT(!mManager);
-  MOZ_ASSERT(mFetchPutList.IsEmpty());
 }
 
 void
 CacheParent::ActorDestroy(ActorDestroyReason aReason)
 {
   MOZ_ASSERT(mManager);
-  for (uint32_t i = 0; i < mFetchPutList.Length(); ++i) {
-    mFetchPutList[i]->ClearListener();
-  }
-  mFetchPutList.Clear();
-  mManager->RemoveListener(this);
   mManager->ReleaseCacheId(mCacheId);
   mManager = nullptr;
 }
 
+PCacheOpParent*
+CacheParent::AllocPCacheOpParent(const CacheOpArgs& aOpArgs)
+{
+  if (aOpArgs.type() != CacheOpArgs::TCacheMatchArgs &&
+      aOpArgs.type() != CacheOpArgs::TCacheMatchAllArgs &&
+      aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs &&
+      aOpArgs.type() != CacheOpArgs::TCachePutAllArgs &&
+      aOpArgs.type() != CacheOpArgs::TCacheDeleteArgs &&
+      aOpArgs.type() != CacheOpArgs::TCacheKeysArgs)
+  {
+    MOZ_CRASH("Invalid operation sent to Cache actor!");
+  }
+
+  return new CacheOpParent(Manager(), mCacheId, aOpArgs);
+}
+
+bool
+CacheParent::DeallocPCacheOpParent(PCacheOpParent* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+bool
+CacheParent::RecvPCacheOpConstructor(PCacheOpParent* aActor,
+                                     const CacheOpArgs& aOpArgs)
+{
+  auto actor = static_cast<CacheOpParent*>(aActor);
+  actor->Execute(mManager);
+  return true;
+}
+
 PCachePushStreamParent*
 CacheParent::AllocPCachePushStreamParent()
 {
   return CachePushStreamParent::Create();
 }
 
 bool
 CacheParent::DeallocPCachePushStreamParent(PCachePushStreamParent* aActor)
@@ -81,243 +94,11 @@ CacheParent::RecvTeardown()
 {
   if (!Send__delete__(this)) {
     // child process is gone, warn and allow actor to clean up normally
     NS_WARNING("Cache failed to send delete.");
   }
   return true;
 }
 
-bool
-CacheParent::RecvMatch(const RequestId& aRequestId, const PCacheRequest& aRequest,
-                       const PCacheQueryParams& aParams)
-{
-  MOZ_ASSERT(mManager);
-  mManager->CacheMatch(this, aRequestId, mCacheId, aRequest,
-                       aParams);
-  return true;
-}
-
-bool
-CacheParent::RecvMatchAll(const RequestId& aRequestId,
-                          const PCacheRequestOrVoid& aRequest,
-                          const PCacheQueryParams& aParams)
-{
-  MOZ_ASSERT(mManager);
-  mManager->CacheMatchAll(this, aRequestId, mCacheId, aRequest, aParams);
-  return true;
-}
-
-bool
-CacheParent::RecvAddAll(const RequestId& aRequestId,
-                        nsTArray<PCacheRequest>&& aRequests)
-{
-  nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreams;
-  requestStreams.SetCapacity(aRequests.Length());
-
-  for (uint32_t i = 0; i < aRequests.Length(); ++i) {
-    requestStreams.AppendElement(DeserializeCacheStream(aRequests[i].body()));
-  }
-
-  nsRefPtr<FetchPut> fetchPut;
-  nsresult rv = FetchPut::Create(this, mManager, aRequestId, mCacheId,
-                                 aRequests, requestStreams,
-                                 getter_AddRefs(fetchPut));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR);
-    ErrorResult error;
-    error.Throw(rv);
-    if (!SendAddAllResponse(aRequestId, error)) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("Cache failed to send AddAll response.");
-    }
-    return true;
-  }
-
-  mFetchPutList.AppendElement(fetchPut.forget());
-
-  return true;
-}
-
-bool
-CacheParent::RecvPut(const RequestId& aRequestId,
-                     const CacheRequestResponse& aPut)
-{
-  MOZ_ASSERT(mManager);
-
-  nsAutoTArray<CacheRequestResponse, 1> putList;
-  putList.AppendElement(aPut);
-
-  nsAutoTArray<nsCOMPtr<nsIInputStream>, 1> requestStreamList;
-  nsAutoTArray<nsCOMPtr<nsIInputStream>, 1> responseStreamList;
-
-  requestStreamList.AppendElement(
-    DeserializeCacheStream(aPut.request().body()));
-  responseStreamList.AppendElement(
-    DeserializeCacheStream(aPut.response().body()));
-
-
-  mManager->CachePutAll(this, aRequestId, mCacheId, putList, requestStreamList,
-                        responseStreamList);
-
-  return true;
-}
-
-bool
-CacheParent::RecvDelete(const RequestId& aRequestId,
-                        const PCacheRequest& aRequest,
-                        const PCacheQueryParams& aParams)
-{
-  MOZ_ASSERT(mManager);
-  mManager->CacheDelete(this, aRequestId, mCacheId, aRequest, aParams);
-  return true;
-}
-
-bool
-CacheParent::RecvKeys(const RequestId& aRequestId,
-                      const PCacheRequestOrVoid& aRequest,
-                      const PCacheQueryParams& aParams)
-{
-  MOZ_ASSERT(mManager);
-  mManager->CacheKeys(this, aRequestId, mCacheId, aRequest, aParams);
-  return true;
-}
-
-void
-CacheParent::OnCacheMatch(RequestId aRequestId, nsresult aRv,
-                          const SavedResponse* aSavedResponse,
-                          StreamList* aStreamList)
-{
-  AutoParentResponseOrVoid response(Manager());
-
-  // no match
-  if (NS_FAILED(aRv) || !aSavedResponse || !aStreamList) {
-    if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("Cache failed to send Match response.");
-    }
-    return;
-  }
-
-  if (aSavedResponse) {
-    response.Add(*aSavedResponse, aStreamList);
-  }
-
-  if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("Cache failed to send Match response.");
-  }
-}
-
-void
-CacheParent::OnCacheMatchAll(RequestId aRequestId, nsresult aRv,
-                             const nsTArray<SavedResponse>& aSavedResponses,
-                             StreamList* aStreamList)
-{
-  AutoParentResponseList responses(Manager(), aSavedResponses.Length());
-
-  for (uint32_t i = 0; i < aSavedResponses.Length(); ++i) {
-    responses.Add(aSavedResponses[i], aStreamList);
-  }
-
-  if (!SendMatchAllResponse(aRequestId, aRv, responses.SendAsResponseList())) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("Cache failed to send MatchAll response.");
-  }
-}
-
-void
-CacheParent::OnCachePutAll(RequestId aRequestId, nsresult aRv)
-{
-  if (!SendPutResponse(aRequestId, aRv)) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("Cache failed to send Put response.");
-  }
-}
-
-void
-CacheParent::OnCacheDelete(RequestId aRequestId, nsresult aRv, bool aSuccess)
-{
-  if (!SendDeleteResponse(aRequestId, aRv, aSuccess)) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("Cache failed to send Delete response.");
-  }
-}
-
-void
-CacheParent::OnCacheKeys(RequestId aRequestId, nsresult aRv,
-                         const nsTArray<SavedRequest>& aSavedRequests,
-                         StreamList* aStreamList)
-{
-  AutoParentRequestList requests(Manager(), aSavedRequests.Length());
-
-  for (uint32_t i = 0; i < aSavedRequests.Length(); ++i) {
-    requests.Add(aSavedRequests[i], aStreamList);
-  }
-
-  if (!SendKeysResponse(aRequestId, aRv, requests.SendAsRequestList())) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("Cache failed to send Keys response.");
-  }
-}
-
-void
-CacheParent::OnFetchPut(FetchPut* aFetchPut, RequestId aRequestId, const ErrorResult& aRv)
-{
-  aFetchPut->ClearListener();
-  mFetchPutList.RemoveElement(aFetchPut);
-  if (!SendAddAllResponse(aRequestId, aRv)) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("Cache failed to send AddAll response.");
-  }
-}
-
-already_AddRefed<nsIInputStream>
-CacheParent::DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid)
-{
-  if (aStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIInputStream> stream;
-  const PCacheReadStream& readStream = aStreamOrVoid.get_PCacheReadStream();
-
-  // Option 1: A push stream actor was sent for nsPipe data
-  if (readStream.pushStreamParent()) {
-    MOZ_ASSERT(!readStream.controlParent());
-    CachePushStreamParent* pushStream =
-      static_cast<CachePushStreamParent*>(readStream.pushStreamParent());
-    stream = pushStream->TakeReader();
-    MOZ_ASSERT(stream);
-    return stream.forget();
-  }
-
-  // Option 2: One of our own ReadStreams was passed back to us with a stream
-  //           control actor.
-  stream = ReadStream::Create(readStream);
-  if (stream) {
-    return stream.forget();
-  }
-
-  // Option 3: A stream was serialized using normal methods.
-  nsAutoTArray<FileDescriptor, 4> fds;
-  if (readStream.fds().type() ==
-      OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
-
-    FileDescriptorSetParent* fdSetActor =
-      static_cast<FileDescriptorSetParent*>(readStream.fds().get_PFileDescriptorSetParent());
-    MOZ_ASSERT(fdSetActor);
-
-    fdSetActor->ForgetFileDescriptors(fds);
-    MOZ_ASSERT(!fds.IsEmpty());
-
-    if (!fdSetActor->Send__delete__(fdSetActor)) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("Cache failed to delete fd set actor.");
-    }
-  }
-
-  return DeserializeInputStream(readStream.params(), fds);
-}
-
 } // namespace cache
 } // namespace dom
 } // namesapce mozilla
--- a/dom/cache/CacheParent.h
+++ b/dom/cache/CacheParent.h
@@ -2,86 +2,55 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef mozilla_dom_cache_CacheParent_h
 #define mozilla_dom_cache_CacheParent_h
 
-#include "mozilla/dom/cache/FetchPut.h"
-#include "mozilla/dom/cache/Manager.h"
 #include "mozilla/dom/cache/PCacheParent.h"
 #include "mozilla/dom/cache/Types.h"
 
-struct nsID;
-template <class T> class nsRefPtr;
-
 namespace mozilla {
 namespace dom {
 namespace cache {
 
-struct SavedResponse;
+class Manager;
 
 class CacheParent final : public PCacheParent
-                        , public Manager::Listener
-                        , public FetchPut::Listener
 {
 public:
   CacheParent(cache::Manager* aManager, CacheId aCacheId);
   virtual ~CacheParent();
 
 private:
-  // PCacheParent method
+  // PCacheParent methods
   virtual void ActorDestroy(ActorDestroyReason aReason) override;
-  virtual PCachePushStreamParent* AllocPCachePushStreamParent() override;
-  virtual bool DeallocPCachePushStreamParent(PCachePushStreamParent* aActor) override;
-  virtual bool RecvTeardown() override;
-  virtual bool
-  RecvMatch(const RequestId& aRequestId, const PCacheRequest& aRequest,
-            const PCacheQueryParams& aParams) override;
+
+  virtual PCacheOpParent*
+  AllocPCacheOpParent(const CacheOpArgs& aOpArgs) override;
+
   virtual bool
-  RecvMatchAll(const RequestId& aRequestId, const PCacheRequestOrVoid& aRequest,
-               const PCacheQueryParams& aParams) override;
-  virtual bool
-  RecvAddAll(const RequestId& aRequestId,
-             nsTArray<PCacheRequest>&& aRequests) override;
-  virtual bool
-  RecvPut(const RequestId& aRequestId,
-          const CacheRequestResponse& aPut) override;
-  virtual bool
-  RecvDelete(const RequestId& aRequestId, const PCacheRequest& aRequest,
-             const PCacheQueryParams& aParams) override;
+  DeallocPCacheOpParent(PCacheOpParent* aActor) override;
+
   virtual bool
-  RecvKeys(const RequestId& aRequestId, const PCacheRequestOrVoid& aRequest,
-           const PCacheQueryParams& aParams) override;
+  RecvPCacheOpConstructor(PCacheOpParent* actor,
+                          const CacheOpArgs& aOpArgs) override;
+
+  virtual PCachePushStreamParent*
+  AllocPCachePushStreamParent() override;
 
-  // Manager::Listener methods
-  virtual void OnCacheMatch(RequestId aRequestId, nsresult aRv,
-                            const SavedResponse* aSavedResponse,
-                            StreamList* aStreamList) override;
-  virtual void OnCacheMatchAll(RequestId aRequestId, nsresult aRv,
-                               const nsTArray<SavedResponse>& aSavedResponses,
-                               StreamList* aStreamList) override;
-  virtual void OnCachePutAll(RequestId aRequestId, nsresult aRv) override;
-  virtual void OnCacheDelete(RequestId aRequestId, nsresult aRv,
-                             bool aSuccess) override;
-  virtual void OnCacheKeys(RequestId aRequestId, nsresult aRv,
-                           const nsTArray<SavedRequest>& aSavedRequests,
-                           StreamList* aStreamList) override;
+  virtual bool
+  DeallocPCachePushStreamParent(PCachePushStreamParent* aActor) override;
 
-  // FetchPut::Listener methods
-  virtual void OnFetchPut(FetchPut* aFetchPut, RequestId aRequestId,
-                          const mozilla::ErrorResult& aRv) override;
-
-  already_AddRefed<nsIInputStream>
-  DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid);
+  virtual bool
+  RecvTeardown() override;
 
   nsRefPtr<cache::Manager> mManager;
   const CacheId mCacheId;
-  nsTArray<nsRefPtr<FetchPut>> mFetchPutList;
 };
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_cache_CacheParent_h
--- a/dom/cache/CachePushStreamChild.h
+++ b/dom/cache/CachePushStreamChild.h
@@ -15,27 +15,30 @@ class nsIAsyncInputStream;
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 class CachePushStreamChild final : public PCachePushStreamChild
                                  , public ActorChild
 {
+  friend class CacheChild;
+
 public:
-  CachePushStreamChild(Feature* aFeature, nsIAsyncInputStream* aStream);
-  ~CachePushStreamChild();
+  void Start();
 
   virtual void StartDestroy() override;
 
-  void Start();
-
 private:
   class Callback;
 
+  // This class must be constructed using CacheChild::CreatePushStream()
+  CachePushStreamChild(Feature* aFeature, nsIAsyncInputStream* aStream);
+  ~CachePushStreamChild();
+
   // PCachePushStreamChild methods
   virtual void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   void DoRead();
 
   void Wait();
 
--- a/dom/cache/CacheStorage.cpp
+++ b/dom/cache/CacheStorage.cpp
@@ -36,34 +36,36 @@ using mozilla::dom::workers::WorkerPriva
 using mozilla::ipc::BackgroundChild;
 using mozilla::ipc::PBackgroundChild;
 using mozilla::ipc::IProtocol;
 using mozilla::ipc::PrincipalInfo;
 using mozilla::ipc::PrincipalToPrincipalInfo;
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::CacheStorage);
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::CacheStorage);
-NS_IMPL_CYCLE_COLLECTION_CLASS(mozilla::dom::cache::CacheStorage)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(mozilla::dom::cache::CacheStorage)
-  tmp->DisconnectFromActor();
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal, mRequestPromises)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(mozilla::dom::cache::CacheStorage)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal, mRequestPromises)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(mozilla::dom::cache::CacheStorage)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::cache::CacheStorage,
+                                      mGlobal);
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CacheStorage)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIIPCBackgroundChildCreateCallback)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
 NS_INTERFACE_MAP_END
 
+// We cannot reference IPC types in a webidl binding implementation header.  So
+// define this in the .cpp and use heap storage in the mPendingRequests list.
+struct CacheStorage::Entry final
+{
+  nsRefPtr<Promise> mPromise;
+  CacheOpArgs mArgs;
+  // We cannot add the requests until after the actor is present.  So store
+  // the request data separately for now.
+  nsRefPtr<InternalRequest> mRequest;
+};
+
 // static
 already_AddRefed<CacheStorage>
 CacheStorage::CreateOnMainThread(Namespace aNamespace, nsIGlobalObject* aGlobal,
                                  nsIPrincipal* aPrincipal, ErrorResult& aRv)
 {
   MOZ_ASSERT(aGlobal);
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(NS_IsMainThread());
@@ -170,146 +172,141 @@ CacheStorage::CacheStorage(Namespace aNa
 }
 
 already_AddRefed<Promise>
 CacheStorage::Match(const RequestOrUSVString& aRequest,
                     const CacheQueryOptions& aOptions, ErrorResult& aRv)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorage);
 
+  if (mFailedActor) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  nsRefPtr<InternalRequest> request = ToInternalRequest(aRequest, IgnoreBody,
+                                                        aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
   nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
   if (!promise) {
     return nullptr;
   }
 
-  if (mFailedActor) {
-    promise->MaybeReject(NS_ERROR_UNEXPECTED);
-    return promise.forget();
-  }
-
-  RequestId requestId = AddRequestPromise(promise, aRv);
+  CacheQueryParams params;
+  ToCacheQueryParams(params, aOptions);
 
-  Entry entry;
-  entry.mRequestId = requestId;
-  entry.mOp = OP_MATCH;
-  entry.mOptions = aOptions;
-  entry.mRequest = ToInternalRequest(aRequest, IgnoreBody, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
+  nsAutoPtr<Entry> entry(new Entry());
+  entry->mPromise = promise;
+  entry->mArgs = StorageMatchArgs(CacheRequest(), params);
+  entry->mRequest = request;
 
-  mPendingRequests.AppendElement(entry);
-
+  mPendingRequests.AppendElement(entry.forget());
   MaybeRunPendingRequests();
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 CacheStorage::Has(const nsAString& aKey, ErrorResult& aRv)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorage);
 
+  if (mFailedActor) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
   nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
   if (!promise) {
     return nullptr;
   }
 
-  if (mFailedActor) {
-    promise->MaybeReject(NS_ERROR_UNEXPECTED);
-    return promise.forget();
-  }
+  nsAutoPtr<Entry> entry(new Entry());
+  entry->mPromise = promise;
+  entry->mArgs = StorageHasArgs(nsString(aKey));
 
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  Entry* entry = mPendingRequests.AppendElement();
-  entry->mRequestId = requestId;
-  entry->mOp = OP_HAS;
-  entry->mKey = aKey;
-
+  mPendingRequests.AppendElement(entry.forget());
   MaybeRunPendingRequests();
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 CacheStorage::Open(const nsAString& aKey, ErrorResult& aRv)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorage);
 
+  if (mFailedActor) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
   nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
   if (!promise) {
     return nullptr;
   }
 
-  if (mFailedActor) {
-    promise->MaybeReject(NS_ERROR_UNEXPECTED);
-    return promise.forget();
-  }
+  nsAutoPtr<Entry> entry(new Entry());
+  entry->mPromise = promise;
+  entry->mArgs = StorageOpenArgs(nsString(aKey));
 
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  Entry* entry = mPendingRequests.AppendElement();
-  entry->mRequestId = requestId;
-  entry->mOp = OP_OPEN;
-  entry->mKey = aKey;
-
+  mPendingRequests.AppendElement(entry.forget());
   MaybeRunPendingRequests();
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 CacheStorage::Delete(const nsAString& aKey, ErrorResult& aRv)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorage);
 
+  if (mFailedActor) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
   nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
   if (!promise) {
     return nullptr;
   }
 
-  if (mFailedActor) {
-    promise->MaybeReject(NS_ERROR_UNEXPECTED);
-    return promise.forget();
-  }
+  nsAutoPtr<Entry> entry(new Entry());
+  entry->mPromise = promise;
+  entry->mArgs = StorageDeleteArgs(nsString(aKey));
 
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  Entry* entry = mPendingRequests.AppendElement();
-  entry->mRequestId = requestId;
-  entry->mOp = OP_DELETE;
-  entry->mKey = aKey;
-
+  mPendingRequests.AppendElement(entry.forget());
   MaybeRunPendingRequests();
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 CacheStorage::Keys(ErrorResult& aRv)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorage);
 
+  if (mFailedActor) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
   nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
   if (!promise) {
     return nullptr;
   }
 
-  if (mFailedActor) {
-    promise->MaybeReject(NS_ERROR_UNEXPECTED);
-    return promise.forget();
-  }
+  nsAutoPtr<Entry> entry(new Entry());
+  entry->mPromise = promise;
+  entry->mArgs = StorageKeysArgs();
 
-  RequestId requestId = AddRequestPromise(promise, aRv);
-
-  Entry* entry = mPendingRequests.AppendElement();
-  entry->mRequestId = requestId;
-  entry->mOp = OP_KEYS;
-
+  mPendingRequests.AppendElement(entry.forget());
   MaybeRunPendingRequests();
 
   return promise.forget();
 }
 
 // static
 bool
 CacheStorage::PrefEnabled(JSContext* aCx, JSObject* aObj)
@@ -366,19 +363,18 @@ CacheStorage::ActorFailed()
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorage);
   MOZ_ASSERT(!mFailedActor);
 
   mFailedActor = true;
   mFeature = nullptr;
 
   for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
-    RequestId requestId = mPendingRequests[i].mRequestId;
-    nsRefPtr<Promise> promise = RemoveRequestPromise(requestId);
-    promise->MaybeReject(NS_ERROR_UNEXPECTED);
+    nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
+    entry->mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
   }
   mPendingRequests.Clear();
 }
 
 void
 CacheStorage::DestroyInternal(CacheStorageChild* aActor)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorage);
@@ -387,127 +383,16 @@ CacheStorage::DestroyInternal(CacheStora
   mActor->ClearListener();
   mActor = nullptr;
 
   // Note that we will never get an actor again in case another request is
   // made before this object is destructed.
   ActorFailed();
 }
 
-void
-CacheStorage::RecvMatchResponse(RequestId aRequestId, nsresult aRv,
-                                const PCacheResponseOrVoid& aResponse)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheStorage);
-
-  // Convert the response immediately if its present.  This ensures that
-  // any stream actors are cleaned up, even if we error out below.
-  nsRefPtr<Response> response;
-  if (aResponse.type() == PCacheResponseOrVoid::TPCacheResponse) {
-    response = ToResponse(aResponse);
-  }
-
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    promise->MaybeReject(aRv);
-    return;
-  }
-
-  // If cache name was specified in the request options and the cache does
-  // not exist, then an error code will already have been set.  If we
-  // still do not have a response, then we just resolve undefined like a
-  // normal Cache::Match.
-  if (!response) {
-    promise->MaybeResolve(JS::UndefinedHandleValue);
-    return;
-  }
-
-  promise->MaybeResolve(response);
-}
-
-void
-CacheStorage::RecvHasResponse(RequestId aRequestId, nsresult aRv, bool aSuccess)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheStorage);
-
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    promise->MaybeReject(aRv);
-    return;
-
-  }
-
-  promise->MaybeResolve(aSuccess);
-}
-
-void
-CacheStorage::RecvOpenResponse(RequestId aRequestId, nsresult aRv,
-                               CacheChild* aActor)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheStorage);
-
-  // Unlike most of our async callback Recv*() methods, this one gets back
-  // an actor.  We need to make sure to clean it up in case of error.
-
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    if (aActor) {
-      // We cannot use the CacheChild::StartDestroy() method because there
-      // is no Cache object associated with the actor yet.  Instead, just
-      // send the underlying Teardown message.
-      unused << aActor->SendTeardown();
-    }
-    promise->MaybeReject(aRv);
-    return;
-  }
-
-  if (!aActor) {
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
-    return;
-  }
-
-  nsRefPtr<Cache> cache = new Cache(mGlobal, aActor);
-  promise->MaybeResolve(cache);
-}
-
-void
-CacheStorage::RecvDeleteResponse(RequestId aRequestId, nsresult aRv,
-                                 bool aSuccess)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheStorage);
-
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    promise->MaybeReject(aRv);
-    return;
-  }
-
-  promise->MaybeResolve(aSuccess);
-}
-
-void
-CacheStorage::RecvKeysResponse(RequestId aRequestId, nsresult aRv,
-                               const nsTArray<nsString>& aKeys)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheStorage);
-
-  nsRefPtr<Promise> promise = RemoveRequestPromise(aRequestId);
-
-  if (NS_FAILED(aRv)) {
-    promise->MaybeReject(aRv);
-    return;
-  }
-
-  promise->MaybeResolve(aKeys);
-}
-
 nsIGlobalObject*
 CacheStorage::GetGlobalObject() const
 {
   return mGlobal;
 }
 
 #ifdef DEBUG
 void
@@ -519,136 +404,46 @@ CacheStorage::AssertOwningThread() const
 
 CachePushStreamChild*
 CacheStorage::CreatePushStream(nsIAsyncInputStream* aStream)
 {
   // This is true because CacheStorage always uses IgnoreBody for requests.
   MOZ_CRASH("CacheStorage should never create a push stream.");
 }
 
-void
-CacheStorage::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
-{
-  // Do nothing.  The Promise will automatically drop the ref to us after
-  // calling the callback.  This is what we want as we only registered in order
-  // to be held alive via the Promise handle.
-}
-
-void
-CacheStorage::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
-{
-  // Do nothing.  The Promise will automatically drop the ref to us after
-  // calling the callback.  This is what we want as we only registered in order
-  // to be held alive via the Promise handle.
-}
-
 CacheStorage::~CacheStorage()
 {
-  DisconnectFromActor();
-}
-
-void
-CacheStorage::DisconnectFromActor()
-{
   NS_ASSERT_OWNINGTHREAD(CacheStorage);
-
   if (mActor) {
     mActor->StartDestroy();
     // DestroyInternal() is called synchronously by StartDestroy().  So we
     // should have already cleared the mActor.
     MOZ_ASSERT(!mActor);
   }
 }
 
 void
 CacheStorage::MaybeRunPendingRequests()
 {
   if (!mActor) {
     return;
   }
 
   for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
-    // Note, the entry can be modified below due to Request/Response body
-    // being marked used.
-    Entry& entry = mPendingRequests[i];
-    RequestId requestId = entry.mRequestId;
-    switch(entry.mOp) {
-      case OP_MATCH:
-      {
-        AutoChildRequest request(this);
-        ErrorResult rv;
-        request.Add(entry.mRequest, IgnoreBody, PassThroughReferrer,
-                    IgnoreInvalidScheme, rv);
-        if (NS_WARN_IF(rv.Failed())) {
-          nsRefPtr<Promise> promise = RemoveRequestPromise(requestId);
-          promise->MaybeReject(rv);
-          break;
-        }
-
-        PCacheQueryParams params;
-        ToPCacheQueryParams(params, entry.mOptions);
-
-        unused << mActor->SendMatch(requestId, request.SendAsRequest(), params);
-        break;
-      }
-      case OP_HAS:
-        unused << mActor->SendHas(requestId, entry.mKey);
-        break;
-      case OP_OPEN:
-        unused << mActor->SendOpen(requestId, entry.mKey);
-        break;
-      case OP_DELETE:
-        unused << mActor->SendDelete(requestId, entry.mKey);
-        break;
-      case OP_KEYS:
-        unused << mActor->SendKeys(requestId);
-        break;
-      default:
-        MOZ_ASSERT_UNREACHABLE("Unknown pending CacheStorage op.");
+    ErrorResult rv;
+    nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
+    AutoChildOpArgs args(this, entry->mArgs);
+    if (entry->mRequest) {
+      args.Add(entry->mRequest, IgnoreBody, PassThroughReferrer,
+               IgnoreInvalidScheme, rv);
     }
+    if (rv.Failed()) {
+      entry->mPromise->MaybeReject(rv);
+      continue;
+    }
+    mActor->ExecuteOp(mGlobal, entry->mPromise, args.SendAsOpArgs());
   }
   mPendingRequests.Clear();
 }
 
-RequestId
-CacheStorage::AddRequestPromise(Promise* aPromise, ErrorResult& aRv)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheStorage);
-  MOZ_ASSERT(aPromise);
-  MOZ_ASSERT(!mRequestPromises.Contains(aPromise));
-
-  // Register ourself as a promise handler so that the promise will hold us
-  // alive.  This allows the client code to drop the ref to the CacheStorage
-  // object and just keep their promise.  This is fairly common in promise
-  // chaining code.
-  aPromise->AppendNativeHandler(this);
-
-  mRequestPromises.AppendElement(aPromise);
-
-  // (Ab)use the promise pointer as our request ID.  This is a fast, thread-safe
-  // way to get a unique ID for the promise to be resolved later.
-  return reinterpret_cast<RequestId>(aPromise);
-}
-
-already_AddRefed<Promise>
-CacheStorage::RemoveRequestPromise(RequestId aRequestId)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheStorage);
-  MOZ_ASSERT(aRequestId != INVALID_REQUEST_ID);
-
-  for (uint32_t i = 0; i < mRequestPromises.Length(); ++i) {
-    nsRefPtr<Promise>& promise = mRequestPromises.ElementAt(i);
-    // To be safe, only cast promise pointers to our integer RequestId
-    // type and never cast an integer to a pointer.
-    if (aRequestId == reinterpret_cast<RequestId>(promise.get())) {
-      nsRefPtr<Promise> ref;
-      ref.swap(promise);
-      mRequestPromises.RemoveElementAt(i);
-      return ref.forget();
-    }
-  }
-  MOZ_ASSERT_UNREACHABLE("Received response without a matching promise!");
-  return nullptr;
-}
-
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/CacheStorage.h
+++ b/dom/cache/CacheStorage.h
@@ -3,17 +3,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/. */
 
 #ifndef mozilla_dom_cache_CacheStorage_h
 #define mozilla_dom_cache_CacheStorage_h
 
 #include "mozilla/dom/CacheBinding.h"
-#include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/cache/Types.h"
 #include "mozilla/dom/cache/TypeUtils.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsISupportsImpl.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 #include "nsIIPCBackgroundChildCreateCallback.h"
@@ -33,25 +32,22 @@ namespace dom {
 class Promise;
 
 namespace workers {
   class WorkerPrivate;
 }
 
 namespace cache {
 
-class CacheChild;
 class CacheStorageChild;
 class Feature;
-class PCacheResponseOrVoid;
 
 class CacheStorage final : public nsIIPCBackgroundChildCreateCallback
                          , public nsWrapperCache
                          , public TypeUtils
-                         , public PromiseNativeHandler
 {
   typedef mozilla::ipc::PBackgroundChild PBackgroundChild;
 
 public:
   static already_AddRefed<CacheStorage>
   CreateOnMainThread(Namespace aNamespace, nsIGlobalObject* aGlobal,
                      nsIPrincipal* aPrincipal, ErrorResult& aRv);
 
@@ -76,89 +72,43 @@ public:
 
   // nsIIPCbackgroundChildCreateCallback methods
   virtual void ActorCreated(PBackgroundChild* aActor) override;
   virtual void ActorFailed() override;
 
   // Called when CacheStorageChild actor is being destroyed
   void DestroyInternal(CacheStorageChild* aActor);
 
-  // Methods forwarded from CacheStorageChild
-  void RecvMatchResponse(RequestId aRequestId, nsresult aRv,
-                         const PCacheResponseOrVoid& aResponse);
-  void RecvHasResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
-  void RecvOpenResponse(RequestId aRequestId, nsresult aRv,
-                        CacheChild* aActor);
-  void RecvDeleteResponse(RequestId aRequestId, nsresult aRv, bool aSuccess);
-  void RecvKeysResponse(RequestId aRequestId, nsresult aRv,
-                        const nsTArray<nsString>& aKeys);
-
   // TypeUtils methods
   virtual nsIGlobalObject* GetGlobalObject() const override;
 #ifdef DEBUG
   virtual void AssertOwningThread() const override;
 #endif
 
   virtual CachePushStreamChild*
   CreatePushStream(nsIAsyncInputStream* aStream) override;
 
-  // PromiseNativeHandler methods
-  virtual void
-  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
-
-  virtual void
-  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
-
 private:
   CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal,
                const mozilla::ipc::PrincipalInfo& aPrincipalInfo, Feature* aFeature);
   ~CacheStorage();
 
-  // Called when we're destroyed or CCed.
-  void DisconnectFromActor();
-
   void MaybeRunPendingRequests();
 
-  RequestId AddRequestPromise(Promise* aPromise, ErrorResult& aRv);
-  already_AddRefed<Promise> RemoveRequestPromise(RequestId aRequestId);
-
-  // Would like to use CacheInitData here, but we cannot because
-  // its an IPC struct which breaks webidl by including windows.h.
   const Namespace mNamespace;
   nsCOMPtr<nsIGlobalObject> mGlobal;
   UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
   nsRefPtr<Feature> mFeature;
+
+  // weak ref cleared in DestroyInternal
   CacheStorageChild* mActor;
-  nsTArray<nsRefPtr<Promise>> mRequestPromises;
-
-  enum Op
-  {
-    OP_MATCH,
-    OP_HAS,
-    OP_OPEN,
-    OP_DELETE,
-    OP_KEYS
-  };
 
-  struct Entry
-  {
-    RequestId mRequestId;
-    Op mOp;
-    // Would prefer to use PCacheRequest/PCacheCacheQueryOptions, but can't
-    // because they introduce a header dependency on windows.h which
-    // breaks the bindings build.
-    nsRefPtr<InternalRequest> mRequest;
-    CacheQueryOptions mOptions;
-    // It would also be nice to union the key with the match args above,
-    // but VS2013 doesn't like these types in unions because of copy
-    // constructors.
-    nsString mKey;
-  };
+  struct Entry;
+  nsTArray<nsAutoPtr<Entry>> mPendingRequests;
 
-  nsTArray<Entry> mPendingRequests;
   bool mFailedActor;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(CacheStorage,
                                            nsIIPCBackgroundChildCreateCallback)
 };
 
--- a/dom/cache/CacheStorageChild.cpp
+++ b/dom/cache/CacheStorageChild.cpp
@@ -3,32 +3,33 @@
 /* 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/. */
 
 #include "mozilla/dom/cache/CacheStorageChild.h"
 
 #include "mozilla/unused.h"
 #include "mozilla/dom/cache/CacheChild.h"
+#include "mozilla/dom/cache/CacheOpChild.h"
 #include "mozilla/dom/cache/CacheStorage.h"
-#include "mozilla/dom/cache/StreamUtils.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 // declared in ActorUtils.h
 void
 DeallocPCacheStorageChild(PCacheStorageChild* aActor)
 {
   delete aActor;
 }
 
 CacheStorageChild::CacheStorageChild(CacheStorage* aListener, Feature* aFeature)
   : mListener(aListener)
+  , mNumChildActors(0)
 {
   MOZ_COUNT_CTOR(cache::CacheStorageChild);
   MOZ_ASSERT(mListener);
 
   SetFeature(aFeature);
 }
 
 CacheStorageChild::~CacheStorageChild()
@@ -42,16 +43,25 @@ void
 CacheStorageChild::ClearListener()
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
   MOZ_ASSERT(mListener);
   mListener = nullptr;
 }
 
 void
+CacheStorageChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
+                             const CacheOpArgs& aArgs)
+{
+  mNumChildActors += 1;
+  unused << SendPCacheOpConstructor(
+    new CacheOpChild(GetFeature(), aGlobal, aPromise), aArgs);
+}
+
+void
 CacheStorageChild::StartDestroy()
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
 
   nsRefPtr<CacheStorage> listener = mListener;
 
   // StartDestroy() can get called from either CacheStorage or the Feature.
   // Theoretically we can get double called if the right race happens.  Handle
@@ -60,16 +70,24 @@ CacheStorageChild::StartDestroy()
     return;
   }
 
   listener->DestroyInternal(this);
 
   // CacheStorage listener should call ClearListener() in DestroyInternal()
   MOZ_ASSERT(!mListener);
 
+  // If we have outstanding child actors, then don't destroy ourself yet.
+  // The child actors should be short lived and we should allow them to complete
+  // if possible.  SendTeardown() will be called when the count drops to zero
+  // in NoteDeletedActor().
+  if (mNumChildActors) {
+    return;
+  }
+
   // Start actor destruction from parent process
   unused << SendTeardown();
 }
 
 void
 CacheStorageChild::ActorDestroy(ActorDestroyReason aReason)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
@@ -78,99 +96,36 @@ CacheStorageChild::ActorDestroy(ActorDes
     listener->DestroyInternal(this);
     // CacheStorage listener should call ClearListener() in DestroyInternal()
     MOZ_ASSERT(!mListener);
   }
 
   RemoveFeature();
 }
 
-bool
-CacheStorageChild::RecvMatchResponse(const RequestId& aRequestId,
-                                     const nsresult& aRv,
-                                     const PCacheResponseOrVoid& aResponseOrVoid)
+PCacheOpChild*
+CacheStorageChild::AllocPCacheOpChild(const CacheOpArgs& aOpArgs)
 {
-  NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
-
-  AddFeatureToStreamChild(aResponseOrVoid, GetFeature());
-
-  nsRefPtr<CacheStorage> listener = mListener;
-  if (!listener) {
-    StartDestroyStreamChild(aResponseOrVoid);
-    return true;
-  }
-
-  listener->RecvMatchResponse(aRequestId, aRv, aResponseOrVoid);
-
-  return true;
-}
-
-bool
-CacheStorageChild::RecvHasResponse(const RequestId& aRequestId,
-                                   const nsresult& aRv,
-                                   const bool& aSuccess)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
-  nsRefPtr<CacheStorage> listener = mListener;
-  if (listener) {
-    listener->RecvHasResponse(aRequestId, aRv, aSuccess);
-  }
-  return true;
+  MOZ_CRASH("CacheOpChild should be manually constructed.");
+  return nullptr;
 }
 
 bool
-CacheStorageChild::RecvOpenResponse(const RequestId& aRequestId,
-                                    const nsresult& aRv,
-                                    PCacheChild* aActor)
+CacheStorageChild::DeallocPCacheOpChild(PCacheOpChild* aActor)
 {
-  NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
-
-  nsRefPtr<CacheStorage> listener = mListener;
-  if (!listener || FeatureNotified()) {
-    if (aActor) {
-      unused << aActor->SendTeardown();
-    }
-    return true;
-  }
-
-  CacheChild* cacheChild = static_cast<CacheChild*>(aActor);
-
-  // Since FeatureNotified() returned false above, we are guaranteed that
-  // the feature won't try to shutdown the actor until after we create the
-  // Cache DOM object in the listener's RecvOpenResponse() method.  This
-  // is important because StartShutdown() expects a Cache object listener.
-  if (cacheChild) {
-    cacheChild->SetFeature(GetFeature());
-  }
-
-  listener->RecvOpenResponse(aRequestId, aRv, cacheChild);
+  delete aActor;
+  NoteDeletedActor();
   return true;
 }
 
-bool
-CacheStorageChild::RecvDeleteResponse(const RequestId& aRequestId,
-                                      const nsresult& aRv,
-                                      const bool& aResult)
+void
+CacheStorageChild::NoteDeletedActor()
 {
-  NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
-  nsRefPtr<CacheStorage> listener = mListener;
-  if (listener) {
-    listener->RecvDeleteResponse(aRequestId, aRv, aResult);
+  MOZ_ASSERT(mNumChildActors);
+  mNumChildActors -= 1;
+  if (!mNumChildActors && !mListener) {
+    unused << SendTeardown();
   }
-  return true;
-}
-
-bool
-CacheStorageChild::RecvKeysResponse(const RequestId& aRequestId,
-                                    const nsresult& aRv,
-                                    nsTArray<nsString>&& aKeys)
-{
-  NS_ASSERT_OWNINGTHREAD(CacheStorageChild);
-  nsRefPtr<CacheStorage> listener = mListener;
-  if (listener) {
-    listener->RecvKeysResponse(aRequestId, aRv, aKeys);
-  }
-  return true;
 }
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/CacheStorageChild.h
+++ b/dom/cache/CacheStorageChild.h
@@ -6,67 +6,72 @@
 
 #ifndef mozilla_dom_cache_CacheStorageChild_h
 #define mozilla_dom_cache_CacheStorageChild_h
 
 #include "mozilla/dom/cache/ActorChild.h"
 #include "mozilla/dom/cache/Types.h"
 #include "mozilla/dom/cache/PCacheStorageChild.h"
 
+class nsIGlobalObject;
+
 namespace mozilla {
 namespace dom {
+
+class Promise;
+
 namespace cache {
 
+class CacheOpArgs;
 class CacheStorage;
 class PCacheChild;
 class Feature;
 
 class CacheStorageChild final : public PCacheStorageChild
                               , public ActorChild
 {
 public:
   CacheStorageChild(CacheStorage* aListener, Feature* aFeature);
   ~CacheStorageChild();
 
   // Must be called by the associated CacheStorage listener in its
-  // ActorDestroy() method.  Also, CacheStorage must Send__delete__() the
+  // ActorDestroy() method.  Also, CacheStorage must call SendDestroy() on the
   // actor in its destructor to trigger ActorDestroy() if it has not been
   // called yet.
   void ClearListener();
 
+  void
+  ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise,
+            const CacheOpArgs& aArgs);
+
   // ActorChild methods
 
   // Synchronously call ActorDestroy on our CacheStorage listener and then start
   // the actor destruction asynchronously from the parent-side.
   virtual void StartDestroy() override;
 
 private:
   // PCacheStorageChild methods
   virtual void ActorDestroy(ActorDestroyReason aReason) override;
 
-  virtual bool RecvMatchResponse(const RequestId& aRequestId,
-                                 const nsresult& aRv,
-                                 const PCacheResponseOrVoid& response) override;
-  virtual bool RecvHasResponse(const cache::RequestId& aRequestId,
-                               const nsresult& aRv,
-                               const bool& aSuccess) override;
-  virtual bool RecvOpenResponse(const cache::RequestId& aRequestId,
-                                const nsresult& aRv,
-                                PCacheChild* aActor) override;
-  virtual bool RecvDeleteResponse(const cache::RequestId& aRequestId,
-                                  const nsresult& aRv,
-                                  const bool& aResult) override;
-  virtual bool RecvKeysResponse(const cache::RequestId& aRequestId,
-                                const nsresult& aRv,
-                                nsTArray<nsString>&& aKeys) override;
+  virtual PCacheOpChild*
+  AllocPCacheOpChild(const CacheOpArgs& aOpArgs) override;
+
+  virtual bool
+  DeallocPCacheOpChild(PCacheOpChild* aActor) override;
+
+  // utility methods
+  void
+  NoteDeletedActor();
 
   // Use a weak ref so actor does not hold DOM object alive past content use.
   // The CacheStorage object must call ClearListener() to null this before its
   // destroyed.
   CacheStorage* MOZ_NON_OWNING_REF mListener;
+  uint32_t mNumChildActors;
 
   NS_DECL_OWNINGTHREAD
 };
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/cache/CacheStorageParent.cpp
+++ b/dom/cache/CacheStorageParent.cpp
@@ -1,38 +1,28 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "mozilla/dom/cache/CacheStorageParent.h"
 
+#include "mozilla/unused.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/cache/ActorUtils.h"
-#include "mozilla/dom/cache/AutoUtils.h"
-#include "mozilla/dom/cache/CacheParent.h"
-#include "mozilla/dom/cache/CacheStreamControlParent.h"
-#include "mozilla/dom/cache/Manager.h"
+#include "mozilla/dom/cache/CacheOpParent.h"
 #include "mozilla/dom/cache/ManagerId.h"
-#include "mozilla/dom/cache/ReadStream.h"
-#include "mozilla/dom/cache/SavedTypes.h"
-#include "mozilla/dom/cache/StreamList.h"
 #include "mozilla/ipc/PBackgroundParent.h"
-#include "mozilla/ipc/InputStreamUtils.h"
-#include "mozilla/ipc/PFileDescriptorSetParent.h"
-#include "mozilla/DebugOnly.h"
-#include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 using mozilla::ipc::PBackgroundParent;
-using mozilla::ipc::PFileDescriptorSetParent;
 using mozilla::ipc::PrincipalInfo;
 
 // declared in ActorUtils.h
 PCacheStorageParent*
 AllocPCacheStorageParent(PBackgroundParent* aManagingActor,
                          Namespace aNamespace,
                          const mozilla::ipc::PrincipalInfo& aPrincipalInfo)
 {
@@ -60,391 +50,93 @@ CacheStorageParent::CacheStorageParent(P
                                                    aPrincipalInfo);
   MOZ_ASSERT(mVerifier);
 }
 
 CacheStorageParent::~CacheStorageParent()
 {
   MOZ_COUNT_DTOR(cache::CacheStorageParent);
   MOZ_ASSERT(!mVerifier);
-  MOZ_ASSERT(!mManager);
 }
 
 void
 CacheStorageParent::ActorDestroy(ActorDestroyReason aReason)
 {
   if (mVerifier) {
-    mVerifier->ClearListener();
+    mVerifier->RemoveListener(this);
     mVerifier = nullptr;
   }
+}
+
+PCacheOpParent*
+CacheStorageParent::AllocPCacheOpParent(const CacheOpArgs& aOpArgs)
+{
+  if (aOpArgs.type() != CacheOpArgs::TStorageMatchArgs &&
+      aOpArgs.type() != CacheOpArgs::TStorageHasArgs &&
+      aOpArgs.type() != CacheOpArgs::TStorageOpenArgs &&
+      aOpArgs.type() != CacheOpArgs::TStorageDeleteArgs &&
+      aOpArgs.type() != CacheOpArgs::TStorageKeysArgs)
+  {
+    MOZ_CRASH("Invalid operation sent to CacheStorage actor!");
+  }
 
-  if (mManager) {
-    MOZ_ASSERT(!mActiveRequests.IsEmpty());
-    mManager->RemoveListener(this);
-    mManager = nullptr;
+  return new CacheOpParent(Manager(), mNamespace, aOpArgs);
+}
+
+bool
+CacheStorageParent::DeallocPCacheOpParent(PCacheOpParent* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+bool
+CacheStorageParent::RecvPCacheOpConstructor(PCacheOpParent* aActor,
+                                            const CacheOpArgs& aOpArgs)
+{
+  auto actor = static_cast<CacheOpParent*>(aActor);
+
+  if (mVerifier) {
+    MOZ_ASSERT(!mManagerId);
+    actor->WaitForVerification(mVerifier);
+    return true;
   }
+
+  if (NS_FAILED(mVerifiedStatus)) {
+    unused << CacheOpParent::Send__delete__(actor, ErrorResult(mVerifiedStatus),
+                                            void_t());
+    return true;
+  }
+
+  MOZ_ASSERT(mManagerId);
+  actor->Execute(mManagerId);
+  return true;
 }
 
 bool
 CacheStorageParent::RecvTeardown()
 {
   if (!Send__delete__(this)) {
     // child process is gone, warn and allow actor to clean up normally
     NS_WARNING("CacheStorage failed to delete actor.");
   }
   return true;
 }
 
-bool
-CacheStorageParent::RecvMatch(const RequestId& aRequestId,
-                              const PCacheRequest& aRequest,
-                              const PCacheQueryParams& aParams)
-{
-  if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
-    if (!SendMatchResponse(aRequestId, mVerifiedStatus, void_t())) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Match response.");
-    }
-    return true;
-  }
-
-  // queue requests if we are still waiting for principal verification
-  if (!mManagerId) {
-    Entry* entry = mPendingRequests.AppendElement();
-    entry->mOp = OP_MATCH;
-    entry->mRequestId = aRequestId;
-    entry->mRequest = aRequest;
-    entry->mParams = aParams;
-    return true;
-  }
-
-  nsRefPtr<cache::Manager> manager;
-  nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    if (!SendMatchResponse(aRequestId, rv, void_t())) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Match response.");
-    }
-    return true;
-  }
-
-  manager->StorageMatch(this, aRequestId, mNamespace, aRequest,
-                        aParams);
-
-  return true;
-}
-
-bool
-CacheStorageParent::RecvHas(const RequestId& aRequestId, const nsString& aKey)
-{
-  if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
-    if (!SendHasResponse(aRequestId, mVerifiedStatus, false)) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Has response.");
-    }
-    return true;
-  }
-
-  // queue requests if we are still waiting for principal verification
-  if (!mManagerId) {
-    Entry* entry = mPendingRequests.AppendElement();
-    entry->mOp = OP_HAS;
-    entry->mRequestId = aRequestId;
-    entry->mKey = aKey;
-    return true;
-  }
-
-  nsRefPtr<cache::Manager> manager;
-  nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    if (!SendHasResponse(aRequestId, rv, false)) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Has response.");
-    }
-    return true;
-  }
-
-  manager->StorageHas(this, aRequestId, mNamespace, aKey);
-
-  return true;
-}
-
-bool
-CacheStorageParent::RecvOpen(const RequestId& aRequestId, const nsString& aKey)
-{
-  if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
-    if (!SendOpenResponse(aRequestId, mVerifiedStatus, nullptr)) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Open response.");
-    }
-    return true;
-  }
-
-  // queue requests if we are still waiting for principal verification
-  if (!mManagerId) {
-    Entry* entry = mPendingRequests.AppendElement();
-    entry->mOp = OP_OPEN;
-    entry->mRequestId = aRequestId;
-    entry->mKey = aKey;
-    return true;
-  }
-
-  nsRefPtr<cache::Manager> manager;
-  nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    if (!SendOpenResponse(aRequestId, rv, nullptr)) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Open response.");
-    }
-    return true;
-  }
-
-  manager->StorageOpen(this, aRequestId, mNamespace, aKey);
-
-  return true;
-}
-
-bool
-CacheStorageParent::RecvDelete(const RequestId& aRequestId,
-                               const nsString& aKey)
-{
-  if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
-    if (!SendDeleteResponse(aRequestId, mVerifiedStatus, false)) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Delete response.");
-    }
-    return true;
-  }
-
-  // queue requests if we are still waiting for principal verification
-  if (!mManagerId) {
-    Entry* entry = mPendingRequests.AppendElement();
-    entry->mOp = OP_DELETE;
-    entry->mRequestId = aRequestId;
-    entry->mKey = aKey;
-    return true;
-  }
-
-  nsRefPtr<cache::Manager> manager;
-  nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    if (!SendDeleteResponse(aRequestId, rv, false)) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Delete response.");
-    }
-    return true;
-  }
-
-  manager->StorageDelete(this, aRequestId, mNamespace, aKey);
-
-  return true;
-}
-
-bool
-CacheStorageParent::RecvKeys(const RequestId& aRequestId)
-{
-  if (NS_WARN_IF(NS_FAILED(mVerifiedStatus))) {
-    if (!SendKeysResponse(aRequestId, mVerifiedStatus, nsTArray<nsString>())) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Keys response.");
-    }
-  }
-
-  // queue requests if we are still waiting for principal verification
-  if (!mManagerId) {
-    Entry* entry = mPendingRequests.AppendElement();
-    entry->mOp = OP_DELETE;
-    entry->mRequestId = aRequestId;
-    return true;
-  }
-
-  nsRefPtr<cache::Manager> manager;
-  nsresult rv = RequestManager(aRequestId, getter_AddRefs(manager));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    if (!SendKeysResponse(aRequestId, rv, nsTArray<nsString>())) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Keys response.");
-    }
-    return true;
-  }
-
-  manager->StorageKeys(this, aRequestId, mNamespace);
-
-  return true;
-}
-
 void
 CacheStorageParent::OnPrincipalVerified(nsresult aRv, ManagerId* aManagerId)
 {
   MOZ_ASSERT(mVerifier);
   MOZ_ASSERT(!mManagerId);
-  MOZ_ASSERT(!mManager);
   MOZ_ASSERT(NS_SUCCEEDED(mVerifiedStatus));
 
   if (NS_WARN_IF(NS_FAILED(aRv))) {
     mVerifiedStatus = aRv;
   }
 
   mManagerId = aManagerId;
-  mVerifier->ClearListener();
+  mVerifier->RemoveListener(this);
   mVerifier = nullptr;
-
-  RetryPendingRequests();
-}
-
-void
-CacheStorageParent::OnStorageMatch(RequestId aRequestId, nsresult aRv,
-                                   const SavedResponse* aSavedResponse,
-                                   StreamList* aStreamList)
-{
-  PCacheResponseOrVoid responseOrVoid;
-
-  ReleaseManager(aRequestId);
-
-  AutoParentResponseOrVoid response(Manager());
-
-  // no match
-  if (NS_FAILED(aRv) || !aSavedResponse) {
-    if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Match response.");
-    }
-    return;
-  }
-
-  if (aSavedResponse) {
-    response.Add(*aSavedResponse, aStreamList);
-  }
-
-  if (!SendMatchResponse(aRequestId, aRv, response.SendAsResponseOrVoid())) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("CacheStorage failed to send Match response.");
-  }
-}
-
-void
-CacheStorageParent::OnStorageHas(RequestId aRequestId, nsresult aRv,
-                                 bool aCacheFound)
-{
-  ReleaseManager(aRequestId);
-  if (!SendHasResponse(aRequestId, aRv, aCacheFound)) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("CacheStorage failed to send Has response.");
-  }
-}
-
-void
-CacheStorageParent::OnStorageOpen(RequestId aRequestId, nsresult aRv,
-                                  CacheId aCacheId)
-{
-  if (NS_FAILED(aRv)) {
-    ReleaseManager(aRequestId);
-    if (!SendOpenResponse(aRequestId, aRv, nullptr)) {
-      // child process is gone, warn and allow actor to clean up normally
-      NS_WARNING("CacheStorage failed to send Open response.");
-    }
-    return;
-  }
-
-  MOZ_ASSERT(mManager);
-  CacheParent* actor = new CacheParent(mManager, aCacheId);
-
-  ReleaseManager(aRequestId);
-
-  PCacheParent* base = Manager()->SendPCacheConstructor(actor);
-  actor = static_cast<CacheParent*>(base);
-  if (!SendOpenResponse(aRequestId, aRv, actor)) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("CacheStorage failed to send Open response.");
-  }
-}
-
-void
-CacheStorageParent::OnStorageDelete(RequestId aRequestId, nsresult aRv,
-                                    bool aCacheDeleted)
-{
-  ReleaseManager(aRequestId);
-  if (!SendDeleteResponse(aRequestId, aRv, aCacheDeleted)) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("CacheStorage failed to send Delete response.");
-  }
-}
-
-void
-CacheStorageParent::OnStorageKeys(RequestId aRequestId, nsresult aRv,
-                                  const nsTArray<nsString>& aKeys)
-{
-  ReleaseManager(aRequestId);
-  if (!SendKeysResponse(aRequestId, aRv, aKeys)) {
-    // child process is gone, warn and allow actor to clean up normally
-    NS_WARNING("CacheStorage failed to send Keys response.");
-  }
-}
-
-void
-CacheStorageParent::RetryPendingRequests()
-{
-  MOZ_ASSERT(mManagerId || NS_FAILED(mVerifiedStatus));
-  for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
-    const Entry& entry = mPendingRequests[i];
-    switch(entry.mOp) {
-      case OP_MATCH:
-        RecvMatch(entry.mRequestId, entry.mRequest, entry.mParams);
-        break;
-      case OP_HAS:
-        RecvHas(entry.mRequestId, entry.mKey);
-        break;
-      case OP_OPEN:
-        RecvOpen(entry.mRequestId, entry.mKey);
-        break;
-      case OP_DELETE:
-        RecvDelete(entry.mRequestId, entry.mKey);
-        break;
-      case OP_KEYS:
-        RecvKeys(entry.mRequestId);
-        break;
-      default:
-        MOZ_ASSERT_UNREACHABLE("Pending request within unknown op");
-    }
-  }
-  mPendingRequests.Clear();
-  mPendingRequests.Compact();
-}
-
-nsresult
-CacheStorageParent::RequestManager(RequestId aRequestId,
-                                   cache::Manager** aManagerOut)
-{
-  MOZ_ASSERT(!mActiveRequests.Contains(aRequestId));
-  nsRefPtr<cache::Manager> ref = mManager;
-  if (!ref) {
-    MOZ_ASSERT(mActiveRequests.IsEmpty());
-    nsresult rv = cache::Manager::GetOrCreate(mManagerId, getter_AddRefs(ref));
-    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-    mManager = ref;
-  }
-  mActiveRequests.AppendElement(aRequestId);
-  ref.forget(aManagerOut);
-  return NS_OK;
-}
-
-void
-CacheStorageParent::ReleaseManager(RequestId aRequestId)
-{
-  // Note that if the child process dies we also clean up the mManager in
-  // ActorDestroy().  There is no race with this method, however, because
-  // ActorDestroy removes this object from the Manager's listener list.
-  // Therefore ReleaseManager() should never be called after ActorDestroy()
-  // runs.
-  MOZ_ASSERT(mManager);
-  MOZ_ASSERT(!mActiveRequests.IsEmpty());
-
-  MOZ_ALWAYS_TRUE(mActiveRequests.RemoveElement(aRequestId));
-
-  if (mActiveRequests.IsEmpty()) {
-    mManager->RemoveListener(this);
-    mManager = nullptr;
-  }
 }
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/CacheStorageParent.h
+++ b/dom/cache/CacheStorageParent.h
@@ -2,107 +2,59 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef mozilla_dom_cache_CacheStorageParent_h
 #define mozilla_dom_cache_CacheStorageParent_h
 
-#include "mozilla/dom/cache/CacheInitData.h"
 #include "mozilla/dom/cache/PCacheStorageParent.h"
-#include "mozilla/dom/cache/Manager.h"
 #include "mozilla/dom/cache/PrincipalVerifier.h"
 #include "mozilla/dom/cache/Types.h"
 
-template <class T> class nsRefPtr;
-
 namespace mozilla {
 namespace dom {
 namespace cache {
 
-class CacheStreamControlParent;
 class ManagerId;
 
 class CacheStorageParent final : public PCacheStorageParent
                                , public PrincipalVerifier::Listener
-                               , public Manager::Listener
 {
 public:
   CacheStorageParent(PBackgroundParent* aManagingActor, Namespace aNamespace,
                      const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
   virtual ~CacheStorageParent();
 
 private:
   // PCacheStorageParent methods
-  virtual void ActorDestroy(ActorDestroyReason aReason) override;
-  virtual bool RecvTeardown() override;
-  virtual bool RecvMatch(const RequestId& aRequestId,
-                         const PCacheRequest& aRequest,
-                         const PCacheQueryParams& aParams) override;
-  virtual bool RecvHas(const RequestId& aRequestId,
-                       const nsString& aKey) override;
-  virtual bool RecvOpen(const RequestId& aRequestId,
-                        const nsString& aKey) override;
-  virtual bool RecvDelete(const RequestId& aRequestId,
-                          const nsString& aKey) override;
-  virtual bool RecvKeys(const RequestId& aRequestId) override;
+  virtual void
+  ActorDestroy(ActorDestroyReason aReason) override;
+
+  virtual PCacheOpParent*
+  AllocPCacheOpParent(const CacheOpArgs& aOpArgs) override;
+
+  virtual bool
+  DeallocPCacheOpParent(PCacheOpParent* aActor) override;
+
+  virtual bool
+  RecvPCacheOpConstructor(PCacheOpParent* actor,
+                          const CacheOpArgs& aOpArgs) override;
+
+  virtual bool
+  RecvTeardown() override;
 
   // PrincipalVerifier::Listener methods
   virtual void OnPrincipalVerified(nsresult aRv,
                                    ManagerId* aManagerId) override;
 
-  // Manager::Listener methods
-  virtual void OnStorageMatch(RequestId aRequestId, nsresult aRv,
-                              const SavedResponse* aResponse,
-                              StreamList* aStreamList) override;
-  virtual void OnStorageHas(RequestId aRequestId, nsresult aRv,
-                            bool aCacheFound) override;
-  virtual void OnStorageOpen(RequestId aRequestId, nsresult aRv,
-                             CacheId aCacheId) override;
-  virtual void OnStorageDelete(RequestId aRequestId, nsresult aRv,
-                               bool aCacheDeleted) override;
-  virtual void OnStorageKeys(RequestId aRequestId, nsresult aRv,
-                             const nsTArray<nsString>& aKeys) override;
-
-  CacheStreamControlParent*
-  SerializeReadStream(CacheStreamControlParent *aStreamControl, const nsID& aId,
-                      StreamList* aStreamList,
-                      PCacheReadStream* aReadStreamOut);
-
-  void RetryPendingRequests();
-
-  nsresult RequestManager(RequestId aRequestId, cache::Manager** aManagerOut);
-  void ReleaseManager(RequestId aRequestId);
-
   const Namespace mNamespace;
   nsRefPtr<PrincipalVerifier> mVerifier;
   nsresult mVerifiedStatus;
   nsRefPtr<ManagerId> mManagerId;
-  nsRefPtr<cache::Manager> mManager;
-
-  enum Op
-  {
-    OP_MATCH,
-    OP_HAS,
-    OP_OPEN,
-    OP_DELETE,
-    OP_KEYS
-  };
-
-  struct Entry
-  {
-    Op mOp;
-    RequestId mRequestId;
-    nsString mKey;
-    PCacheRequest mRequest;
-    PCacheQueryParams mParams;
-  };
-
-  nsTArray<Entry> mPendingRequests;
-  nsTArray<RequestId> mActiveRequests;
 };
 
 } // namesapce cache
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_cache_CacheStorageParent_h
--- a/dom/cache/CacheStreamControlChild.cpp
+++ b/dom/cache/CacheStreamControlChild.cpp
@@ -4,17 +4,17 @@
  * 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/. */
 
 #include "mozilla/dom/cache/CacheStreamControlChild.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/cache/ActorUtils.h"
-#include "mozilla/dom/cache/PCacheTypes.h"
+#include "mozilla/dom/cache/CacheTypes.h"
 #include "mozilla/dom/cache/ReadStream.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PFileDescriptorSetChild.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace dom {
@@ -36,16 +36,17 @@ AllocPCacheStreamControlChild()
 void
 DeallocPCacheStreamControlChild(PCacheStreamControlChild* aActor)
 {
   delete aActor;
 }
 
 CacheStreamControlChild::CacheStreamControlChild()
   : mDestroyStarted(false)
+  , mDestroyDelayed(false)
 {
   MOZ_COUNT_CTOR(cache::CacheStreamControlChild);
 }
 
 CacheStreamControlChild::~CacheStreamControlChild()
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
   MOZ_COUNT_DTOR(cache::CacheStreamControlChild);
@@ -58,31 +59,46 @@ CacheStreamControlChild::StartDestroy()
   // This can get called twice under some circumstances.  For example, if the
   // actor is added to a Feature that has already been notified and the Cache
   // actor has no mListener.
   if (mDestroyStarted) {
     return;
   }
   mDestroyStarted = true;
 
+  // If any of the streams have started to be read, then wait for them to close
+  // naturally.
+  if (HasEverBeenRead()) {
+    // Note that we are delaying so that we can re-check for active streams
+    // in NoteClosedAfterForget().
+    mDestroyDelayed = true;
+    return;
+  }
+
+  // Otherwise, if the streams have not been touched then just pre-emptively
+  // close them now.  This handles the case where someone retrieves a Response
+  // from the Cache, but never accesses the body.  We should not keep the
+  // Worker alive until that Response is GC'd just because of its ignored
+  // body stream.
+
   // Begin shutting down all streams.  This is the same as if the parent had
   // asked us to shutdown.  So simulate the CloseAll IPC message.
   RecvCloseAll();
 }
 
 void
-CacheStreamControlChild::SerializeControl(PCacheReadStream* aReadStreamOut)
+CacheStreamControlChild::SerializeControl(CacheReadStream* aReadStreamOut)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
   aReadStreamOut->controlParent() = nullptr;
   aReadStreamOut->controlChild() = this;
 }
 
 void
-CacheStreamControlChild::SerializeFds(PCacheReadStream* aReadStreamOut,
+CacheStreamControlChild::SerializeFds(CacheReadStream* aReadStreamOut,
                                       const nsTArray<FileDescriptor>& aFds)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
   PFileDescriptorSetChild* fdSet = nullptr;
   if (!aFds.IsEmpty()) {
     fdSet = Manager()->SendPFileDescriptorSetConstructor(aFds[0]);
     for (uint32_t i = 1; i < aFds.Length(); ++i) {
       unused << fdSet->SendAddFileDescriptor(aFds[i]);
@@ -92,17 +108,17 @@ CacheStreamControlChild::SerializeFds(PC
   if (fdSet) {
     aReadStreamOut->fds() = fdSet;
   } else {
     aReadStreamOut->fds() = void_t();
   }
 }
 
 void
-CacheStreamControlChild::DeserializeFds(const PCacheReadStream& aReadStream,
+CacheStreamControlChild::DeserializeFds(const CacheReadStream& aReadStream,
                                         nsTArray<FileDescriptor>& aFdsOut)
 {
   if (aReadStream.fds().type() !=
       OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
     return;
   }
 
   auto fdSetActor = static_cast<FileDescriptorSetChild*>(
@@ -115,16 +131,25 @@ CacheStreamControlChild::DeserializeFds(
   unused << fdSetActor->Send__delete__(fdSetActor);
 }
 
 void
 CacheStreamControlChild::NoteClosedAfterForget(const nsID& aId)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
   unused << SendNoteClosed(aId);
+
+  // A stream has closed.  If we delayed StartDestry() due to this stream
+  // being read, then we should check to see if any of the remaining streams
+  // are active.  If none of our other streams have been read, then we can
+  // proceed with the shutdown now.
+  if (mDestroyDelayed && !HasEverBeenRead()) {
+    mDestroyDelayed = false;
+    RecvCloseAll();
+  }
 }
 
 #ifdef DEBUG
 void
 CacheStreamControlChild::AssertOwningThread()
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
 }
--- a/dom/cache/CacheStreamControlChild.h
+++ b/dom/cache/CacheStreamControlChild.h
@@ -26,24 +26,24 @@ public:
   CacheStreamControlChild();
   ~CacheStreamControlChild();
 
   // ActorChild methods
   virtual void StartDestroy() override;
 
   // StreamControl methods
   virtual void
-  SerializeControl(PCacheReadStream* aReadStreamOut) override;
+  SerializeControl(CacheReadStream* aReadStreamOut) override;
 
   virtual void
-  SerializeFds(PCacheReadStream* aReadStreamOut,
+  SerializeFds(CacheReadStream* aReadStreamOut,
                const nsTArray<mozilla::ipc::FileDescriptor>& aFds) override;
 
   virtual void
-  DeserializeFds(const PCacheReadStream& aReadStream,
+  DeserializeFds(const CacheReadStream& aReadStream,
                  nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) override;
 
 private:
   virtual void
   NoteClosedAfterForget(const nsID& aId) override;
 
 #ifdef DEBUG
   virtual void
@@ -51,16 +51,17 @@ private:
 #endif
 
   // PCacheStreamControlChild methods
   virtual void ActorDestroy(ActorDestroyReason aReason) override;
   virtual bool RecvClose(const nsID& aId) override;
   virtual bool RecvCloseAll() override;
 
   bool mDestroyStarted;
+  bool mDestroyDelayed;
 
   NS_DECL_OWNINGTHREAD
 };
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/cache/CacheStreamControlParent.cpp
+++ b/dom/cache/CacheStreamControlParent.cpp
@@ -3,17 +3,17 @@
 /* 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/. */
 
 #include "mozilla/dom/cache/CacheStreamControlParent.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/unused.h"
-#include "mozilla/dom/cache/PCacheTypes.h"
+#include "mozilla/dom/cache/CacheTypes.h"
 #include "mozilla/dom/cache/ReadStream.h"
 #include "mozilla/dom/cache/StreamList.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/PBackgroundParent.h"
 #include "mozilla/ipc/PFileDescriptorSetParent.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
@@ -40,25 +40,25 @@ CacheStreamControlParent::CacheStreamCon
 CacheStreamControlParent::~CacheStreamControlParent()
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
   MOZ_ASSERT(!mStreamList);
   MOZ_COUNT_DTOR(cache::CacheStreamControlParent);
 }
 
 void
-CacheStreamControlParent::SerializeControl(PCacheReadStream* aReadStreamOut)
+CacheStreamControlParent::SerializeControl(CacheReadStream* aReadStreamOut)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
   aReadStreamOut->controlChild() = nullptr;
   aReadStreamOut->controlParent() = this;
 }
 
 void
-CacheStreamControlParent::SerializeFds(PCacheReadStream* aReadStreamOut,
+CacheStreamControlParent::SerializeFds(CacheReadStream* aReadStreamOut,
                                        const nsTArray<FileDescriptor>& aFds)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
   PFileDescriptorSetParent* fdSet = nullptr;
   if (!aFds.IsEmpty()) {
     fdSet = Manager()->SendPFileDescriptorSetConstructor(aFds[0]);
     for (uint32_t i = 1; i < aFds.Length(); ++i) {
       unused << fdSet->SendAddFileDescriptor(aFds[i]);
@@ -68,17 +68,17 @@ CacheStreamControlParent::SerializeFds(P
   if (fdSet) {
     aReadStreamOut->fds() = fdSet;
   } else {
     aReadStreamOut->fds() = void_t();
   }
 }
 
 void
-CacheStreamControlParent::DeserializeFds(const PCacheReadStream& aReadStream,
+CacheStreamControlParent::DeserializeFds(const CacheReadStream& aReadStream,
                                          nsTArray<FileDescriptor>& aFdsOut)
 {
   if (aReadStream.fds().type() !=
       OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
     return;
   }
 
   FileDescriptorSetParent* fdSetActor =
--- a/dom/cache/CacheStreamControlParent.h
+++ b/dom/cache/CacheStreamControlParent.h
@@ -27,24 +27,24 @@ public:
 
   void SetStreamList(StreamList* aStreamList);
   void Close(const nsID& aId);
   void CloseAll();
   void Shutdown();
 
   // StreamControl methods
   virtual void
-  SerializeControl(PCacheReadStream* aReadStreamOut) override;
+  SerializeControl(CacheReadStream* aReadStreamOut) override;
 
   virtual void
-  SerializeFds(PCacheReadStream* aReadStreamOut,
+  SerializeFds(CacheReadStream* aReadStreamOut,
                const nsTArray<mozilla::ipc::FileDescriptor>& aFds) override;
 
   virtual void
-  DeserializeFds(const PCacheReadStream& aReadStream,
+  DeserializeFds(const CacheReadStream& aReadStream,
                  nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) override;
 
 private:
   virtual void
   NoteClosedAfterForget(const nsID& aId) override;
 
 #ifdef DEBUG
   virtual void
rename from dom/cache/PCacheTypes.ipdlh
rename to dom/cache/CacheTypes.ipdlh
--- a/dom/cache/PCacheTypes.ipdlh
+++ b/dom/cache/CacheTypes.ipdlh
@@ -1,95 +1,244 @@
 /* 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/. */
 
+include protocol PCache;
 include protocol PCachePushStream;
 include protocol PCacheStreamControl;
-include PHeaders;
 include InputStreamParams;
 
-using HeadersGuardEnum from "mozilla/dom/FetchIPCUtils.h";
-using RequestCredentials from "mozilla/dom/FetchIPCUtils.h";
-using RequestMode from "mozilla/dom/FetchIPCUtils.h";
-using RequestCache from "mozilla/dom/FetchIPCUtils.h";
-using RequestContext from "mozilla/dom/FetchIPCUtils.h";
-using mozilla::dom::ResponseType from "mozilla/dom/FetchIPCUtils.h";
+using HeadersGuardEnum from "mozilla/dom/cache/IPCUtils.h";
+using RequestCredentials from "mozilla/dom/cache/IPCUtils.h";
+using RequestMode from "mozilla/dom/cache/IPCUtils.h";
+using RequestCache from "mozilla/dom/cache/IPCUtils.h";
+using RequestContext from "mozilla/dom/cache/IPCUtils.h";
+using ResponseType from "mozilla/dom/cache/IPCUtils.h";
 using mozilla::void_t from "ipc/IPCMessageUtils.h";
 using struct nsID from "nsID.h";
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
-struct PCacheQueryParams
+struct CacheQueryParams
 {
   bool ignoreSearch;
   bool ignoreMethod;
   bool ignoreVary;
   bool cacheNameSet;
   nsString cacheName;
 };
 
-struct PCacheReadStream
+struct CacheReadStream
 {
   nsID id;
   OptionalInputStreamParams params;
   OptionalFileDescriptorSet fds;
   nullable PCacheStreamControl control;
   nullable PCachePushStream pushStream;
 };
 
-union PCacheReadStreamOrVoid
+union CacheReadStreamOrVoid
 {
   void_t;
-  PCacheReadStream;
+  CacheReadStream;
 };
 
-struct PCacheRequest
+struct HeadersEntry
+{
+  nsCString name;
+  nsCString value;
+};
+
+struct CacheRequest
 {
   nsCString method;
   nsString url;
   nsString urlWithoutQuery;
-  PHeadersEntry[] headers;
+  HeadersEntry[] headers;
   HeadersGuardEnum headersGuard;
   nsString referrer;
   RequestMode mode;
   RequestCredentials credentials;
-  PCacheReadStreamOrVoid body;
+  CacheReadStreamOrVoid body;
   uint32_t contentPolicyType;
   RequestContext context;
   RequestCache requestCache;
 };
 
-union PCacheRequestOrVoid
+union CacheRequestOrVoid
 {
   void_t;
-  PCacheRequest;
+  CacheRequest;
 };
 
-struct PCacheResponse
+struct CacheResponse
 {
   ResponseType type;
   nsString url;
   uint32_t status;
   nsCString statusText;
-  PHeadersEntry[] headers;
+  HeadersEntry[] headers;
   HeadersGuardEnum headersGuard;
-  PCacheReadStreamOrVoid body;
+  CacheReadStreamOrVoid body;
   nsCString securityInfo;
 };
 
-union PCacheResponseOrVoid
+union CacheResponseOrVoid
 {
   void_t;
-  PCacheResponse;
+  CacheResponse;
 };
 
 struct CacheRequestResponse
 {
-  PCacheRequest request;
-  PCacheResponse response;
+  CacheRequest request;
+  CacheResponse response;
+};
+
+struct CacheMatchArgs
+{
+  CacheRequest request;
+  CacheQueryParams params;
+};
+
+struct CacheMatchAllArgs
+{
+  CacheRequestOrVoid requestOrVoid;
+  CacheQueryParams params;
+};
+
+struct CacheAddAllArgs
+{
+  CacheRequest[] requestList;
+};
+
+struct CachePutAllArgs
+{
+  CacheRequestResponse[] requestResponseList;
+};
+
+struct CacheDeleteArgs
+{
+  CacheRequest request;
+  CacheQueryParams params;
+};
+
+struct CacheKeysArgs
+{
+  CacheRequestOrVoid requestOrVoid;
+  CacheQueryParams params;
+};
+
+struct StorageMatchArgs
+{
+  CacheRequest request;
+  CacheQueryParams params;
+};
+
+struct StorageHasArgs
+{
+  nsString key;
+};
+
+struct StorageOpenArgs
+{
+  nsString key;
+};
+
+struct StorageDeleteArgs
+{
+  nsString key;
+};
+
+struct StorageKeysArgs
+{
+};
+
+union CacheOpArgs
+{
+  CacheMatchArgs;
+  CacheMatchAllArgs;
+  CacheAddAllArgs;
+  CachePutAllArgs;
+  CacheDeleteArgs;
+  CacheKeysArgs;
+  StorageMatchArgs;
+  StorageHasArgs;
+  StorageOpenArgs;
+  StorageDeleteArgs;
+  StorageKeysArgs;
+};
+
+struct CacheMatchResult
+{
+  CacheResponseOrVoid responseOrVoid;
+};
+
+struct CacheMatchAllResult
+{
+  CacheResponse[] responseList;
+};
+
+struct CacheAddAllResult
+{
+};
+
+struct CachePutAllResult
+{
+};
+
+struct CacheDeleteResult
+{
+  bool success;
+};
+
+struct CacheKeysResult
+{
+  CacheRequest[] requestList;
+};
+
+struct StorageMatchResult
+{
+  CacheResponseOrVoid responseOrVoid;
+};
+
+struct StorageHasResult
+{
+  bool success;
+};
+
+struct StorageOpenResult
+{
+  nullable PCache actor;
+};
+
+struct StorageDeleteResult
+{
+  bool success;
+};
+
+struct StorageKeysResult
+{
+  nsString[] keyList;
+};
+
+union CacheOpResult
+{
+  void_t;
+  CacheMatchResult;
+  CacheMatchAllResult;
+  CacheAddAllResult;
+  CachePutAllResult;
+  CacheDeleteResult;
+  CacheKeysResult;
+  StorageMatchResult;
+  StorageHasResult;
+  StorageOpenResult;
+  StorageDeleteResult;
+  StorageKeysResult;
 };
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/Context.cpp
+++ b/dom/cache/Context.cpp
@@ -727,16 +727,17 @@ Context::Context(Manager* aManager)
 
 void
 Context::Dispatch(nsIEventTarget* aTarget, Action* aAction)
 {
   NS_ASSERT_OWNINGTHREAD(Context);
   MOZ_ASSERT(aTarget);
   MOZ_ASSERT(aAction);
 
+  MOZ_ASSERT(mState != STATE_CONTEXT_CANCELED);
   if (mState == STATE_CONTEXT_CANCELED) {
     return;
   } else if (mState == STATE_CONTEXT_INIT) {
     PendingAction* pending = mPendingActions.AppendElement();
     pending->mTarget = aTarget;
     pending->mAction = aAction;
     return;
   }
@@ -761,21 +762,28 @@ Context::CancelAll()
     ActivityList::ForwardIterator iter(mActivityList);
     while (iter.HasMore()) {
       iter.GetNext()->Cancel();
     }
   }
   AllowToClose();
 }
 
+bool
+Context::IsCanceled() const
+{
+  NS_ASSERT_OWNINGTHREAD(Context);
+  return mState == STATE_CONTEXT_CANCELED;
+}
+
 void
 Context::Invalidate()
 {
   NS_ASSERT_OWNINGTHREAD(Context);
-  mManager->Invalidate();
+  mManager->NoteClosing();
   CancelAll();
 }
 
 void
 Context::AllowToClose()
 {
   NS_ASSERT_OWNINGTHREAD(Context);
   if (mThreadsafeHandle) {
--- a/dom/cache/Context.h
+++ b/dom/cache/Context.h
@@ -121,16 +121,19 @@ public:
 
   // Cancel any Actions running or waiting to run.  This should allow the
   // Context to be released and Listener::RemoveContext() will be called
   // when complete.
   //
   // Only callable from the thread that created the Context.
   void CancelAll();
 
+  // True if CancelAll() has been called.
+  bool IsCanceled() const;
+
   // Like CancelAll(), but also marks the Manager as "invalid".
   void Invalidate();
 
   // Remove any self references and allow the Context to be released when
   // there are no more Actions to process.
   void AllowToClose();
 
   // Cancel any Actions running or waiting to run that operate on the given
--- a/dom/cache/DBAction.cpp
+++ b/dom/cache/DBAction.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/dom/quota/PersistenceType.h"
 #include "mozilla/net/nsFileProtocolHandler.h"
 #include "mozIStorageConnection.h"
 #include "mozIStorageService.h"
 #include "mozStorageCID.h"
 #include "nsIFile.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
+#include "nsThreadUtils.h"
 #include "DBSchema.h"
 #include "FileUtils.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
@@ -141,40 +142,40 @@ DBAction::OpenConnection(const QuotaInfo
     rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
   }
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   // Check the schema to make sure it is not too old.
   int32_t schemaVersion = 0;
   rv = conn->GetSchemaVersion(&schemaVersion);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
-  if (schemaVersion > 0 && schemaVersion < DBSchema::kMaxWipeSchemaVersion) {
+  if (schemaVersion > 0 && schemaVersion < db::kMaxWipeSchemaVersion) {
     conn = nullptr;
     rv = WipeDatabase(dbFile, aDBDir);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
   }
 
-  rv = DBSchema::InitializeConnection(conn);
+  rv = db::InitializeConnection(conn);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   conn.forget(aConnOut);
 
   return rv;
 }
 
 nsresult
 DBAction::WipeDatabase(nsIFile* aDBFile, nsIFile* aDBDir)
 {
   nsresult rv = aDBFile->Remove(false);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   // Delete the morgue as well.
-  rv = FileUtils::BodyDeleteDir(aDBDir);
+  rv = BodyDeleteDir(aDBDir);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
 SyncDBAction::SyncDBAction(Mode aMode)
   : DBAction(aMode)
 {
--- a/dom/cache/DBAction.h
+++ b/dom/cache/DBAction.h
@@ -3,17 +3,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/. */
 
 #ifndef mozilla_dom_cache_DBAction_h
 #define mozilla_dom_cache_DBAction_h
 
 #include "mozilla/dom/cache/Action.h"
-#include "mozilla/dom/cache/CacheInitData.h"
 #include "nsRefPtr.h"
 #include "nsString.h"
 
 class mozIStorageConnection;
 class nsIFile;
 
 namespace mozilla {
 namespace dom {
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -3,37 +3,44 @@
 /* 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/. */
 
 #include "mozilla/dom/cache/DBSchema.h"
 
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/dom/InternalHeaders.h"
-#include "mozilla/dom/cache/PCacheTypes.h"
+#include "mozilla/dom/cache/CacheTypes.h"
 #include "mozilla/dom/cache/SavedTypes.h"
+#include "mozilla/dom/cache/Types.h"
+#include "mozilla/dom/cache/TypeUtils.h"
 #include "mozIStorageConnection.h"
 #include "mozIStorageStatement.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsCRT.h"
 #include "nsHttp.h"
 #include "mozilla/dom/HeadersBinding.h"
 #include "mozilla/dom/RequestBinding.h"
 #include "mozilla/dom/ResponseBinding.h"
-#include "Types.h"
 #include "nsIContentPolicy.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
+namespace db {
 
-const int32_t DBSchema::kMaxWipeSchemaVersion = 6;
-const int32_t DBSchema::kLatestSchemaVersion = 6;
-const int32_t DBSchema::kMaxEntriesPerStatement = 255;
+const int32_t kMaxWipeSchemaVersion = 6;
+
+namespace {
+
+const int32_t kLatestSchemaVersion = 6;
+const int32_t kMaxEntriesPerStatement = 255;
+
+} // anonymous namespace
 
 // If any of the static_asserts below fail, it means that you have changed
 // the corresponding WebIDL enum in a way that may be incompatible with the
 // existing data stored in the DOM Cache.  You would need to update the Cache
 // database schema accordingly and adjust the failing static_assert.
 static_assert(int(HeadersGuardEnum::None) == 0 &&
               int(HeadersGuardEnum::Request) == 1 &&
               int(HeadersGuardEnum::Request_no_cors) == 2 &&
@@ -135,21 +142,58 @@ static_assert(nsIContentPolicy::TYPE_INV
               nsIContentPolicy::TYPE_WEBSOCKET == 16 &&
               nsIContentPolicy::TYPE_CSP_REPORT == 17 &&
               nsIContentPolicy::TYPE_XSLT == 18 &&
               nsIContentPolicy::TYPE_BEACON == 19 &&
               nsIContentPolicy::TYPE_FETCH == 20 &&
               nsIContentPolicy::TYPE_IMAGESET == 21,
               "nsContentPolicytType values are as expected");
 
-using mozilla::void_t;
+namespace {
+
+typedef int32_t EntryId;
 
-// static
+static nsresult QueryAll(mozIStorageConnection* aConn, CacheId aCacheId,
+                         nsTArray<EntryId>& aEntryIdListOut);
+static nsresult QueryCache(mozIStorageConnection* aConn, CacheId aCacheId,
+                           const CacheRequest& aRequest,
+                           const CacheQueryParams& aParams,
+                           nsTArray<EntryId>& aEntryIdListOut,
+                           uint32_t aMaxResults = UINT32_MAX);
+static nsresult MatchByVaryHeader(mozIStorageConnection* aConn,
+                                  const CacheRequest& aRequest,
+                                  EntryId entryId, bool* aSuccessOut);
+static nsresult DeleteEntries(mozIStorageConnection* aConn,
+                              const nsTArray<EntryId>& aEntryIdList,
+                              nsTArray<nsID>& aDeletedBodyIdListOut,
+                              uint32_t aPos=0, int32_t aLen=-1);
+static nsresult InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
+                            const CacheRequest& aRequest,
+                            const nsID* aRequestBodyId,
+                            const CacheResponse& aResponse,
+                            const nsID* aResponseBodyId);
+static nsresult ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
+                             SavedResponse* aSavedResponseOut);
+static nsresult ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
+                            SavedRequest* aSavedRequestOut);
+
+static void AppendListParamsToQuery(nsACString& aQuery,
+                                    const nsTArray<EntryId>& aEntryIdList,
+                                    uint32_t aPos, int32_t aLen);
+static nsresult BindListParamsToQuery(mozIStorageStatement* aState,
+                                      const nsTArray<EntryId>& aEntryIdList,
+                                      uint32_t aPos, int32_t aLen);
+static nsresult BindId(mozIStorageStatement* aState, uint32_t aPos,
+                       const nsID* aId);
+static nsresult ExtractId(mozIStorageStatement* aState, uint32_t aPos,
+                          nsID* aIdOut);
+} // anonymous namespace
+
 nsresult
-DBSchema::CreateSchema(mozIStorageConnection* aConn)
+CreateSchema(mozIStorageConnection* aConn)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   nsAutoCString pragmas(
     // Enable auto-vaccum but in incremental mode in order to avoid doing a lot
     // of work at the end of each transaction.
     "PRAGMA auto_vacuum = INCREMENTAL; "
@@ -279,19 +323,18 @@ DBSchema::CreateSchema(mozIStorageConnec
 
   if (schemaVersion != kLatestSchemaVersion) {
     return NS_ERROR_FAILURE;
   }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::InitializeConnection(mozIStorageConnection* aConn)
+InitializeConnection(mozIStorageConnection* aConn)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   // This function needs to perform per-connection initialization tasks that
   // need to happen regardless of the schema.
 
   nsAutoCString pragmas(
@@ -310,19 +353,18 @@ DBSchema::InitializeConnection(mozIStora
   );
 
   nsresult rv = aConn->ExecuteSimpleSQL(pragmas);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return NS_OK;
 }
 
-// static
 nsresult
-DBSchema::CreateCache(mozIStorageConnection* aConn, CacheId* aCacheIdOut)
+CreateCacheId(mozIStorageConnection* aConn, CacheId* aCacheIdOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   MOZ_ASSERT(aCacheIdOut);
 
   nsresult rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "INSERT INTO caches DEFAULT VALUES;"
   ));
@@ -340,20 +382,19 @@ DBSchema::CreateCache(mozIStorageConnect
   if (NS_WARN_IF(!hasMoreData)) { return NS_ERROR_UNEXPECTED; }
 
   rv = state->GetInt64(0, aCacheIdOut);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::DeleteCache(mozIStorageConnection* aConn, CacheId aCacheId,
-                      nsTArray<nsID>& aDeletedBodyIdListOut)
+DeleteCacheId(mozIStorageConnection* aConn, CacheId aCacheId,
+              nsTArray<nsID>& aDeletedBodyIdListOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   // Delete the bodies explicitly as we need to read out the body IDs
   // anyway.  These body IDs must be deleted one-by-one as content may
   // still be referencing them invidivually.
   nsAutoTArray<EntryId, 256> matches;
@@ -374,20 +415,19 @@ DBSchema::DeleteCache(mozIStorageConnect
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->Execute();
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::IsCacheOrphaned(mozIStorageConnection* aConn,
-                          CacheId aCacheId, bool* aOrphanedOut)
+IsCacheOrphaned(mozIStorageConnection* aConn, CacheId aCacheId,
+                bool* aOrphanedOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   MOZ_ASSERT(aOrphanedOut);
 
   // err on the side of not deleting user data
   *aOrphanedOut = false;
 
@@ -409,23 +449,22 @@ DBSchema::IsCacheOrphaned(mozIStorageCon
   rv = state->GetInt32(0, &refCount);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   *aOrphanedOut = refCount == 0;
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
-                     const PCacheRequest& aRequest,
-                     const PCacheQueryParams& aParams,
-                     bool* aFoundResponseOut,
-                     SavedResponse* aSavedResponseOut)
+CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
+           const CacheRequest& aRequest,
+           const CacheQueryParams& aParams,
+           bool* aFoundResponseOut,
+           SavedResponse* aSavedResponseOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   MOZ_ASSERT(aFoundResponseOut);
   MOZ_ASSERT(aSavedResponseOut);
 
   *aFoundResponseOut = false;
 
@@ -441,29 +480,28 @@ DBSchema::CacheMatch(mozIStorageConnecti
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   aSavedResponseOut->mCacheId = aCacheId;
   *aFoundResponseOut = true;
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
-                        const PCacheRequestOrVoid& aRequestOrVoid,
-                        const PCacheQueryParams& aParams,
-                        nsTArray<SavedResponse>& aSavedResponsesOut)
+CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
+              const CacheRequestOrVoid& aRequestOrVoid,
+              const CacheQueryParams& aParams,
+              nsTArray<SavedResponse>& aSavedResponsesOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   nsresult rv;
 
   nsAutoTArray<EntryId, 256> matches;
-  if (aRequestOrVoid.type() == PCacheRequestOrVoid::Tvoid_t) {
+  if (aRequestOrVoid.type() == CacheRequestOrVoid::Tvoid_t) {
     rv = QueryAll(aConn, aCacheId, matches);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   } else {
     rv = QueryCache(aConn, aCacheId, aRequestOrVoid, aParams, matches);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   }
 
   // TODO: replace this with a bulk load using SQL IN clause (bug 1110458)
@@ -473,50 +511,48 @@ DBSchema::CacheMatchAll(mozIStorageConne
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     savedResponse.mCacheId = aCacheId;
     aSavedResponsesOut.AppendElement(savedResponse);
   }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
-                   const PCacheRequest& aRequest,
-                   const nsID* aRequestBodyId,
-                   const PCacheResponse& aResponse,
-                   const nsID* aResponseBodyId,
-                   nsTArray<nsID>& aDeletedBodyIdListOut)
+CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
+         const CacheRequest& aRequest,
+         const nsID* aRequestBodyId,
+         const CacheResponse& aResponse,
+         const nsID* aResponseBodyId,
+         nsTArray<nsID>& aDeletedBodyIdListOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
-  PCacheQueryParams params(false, false, false, false,
+  CacheQueryParams params(false, false, false, false,
                            NS_LITERAL_STRING(""));
   nsAutoTArray<EntryId, 256> matches;
   nsresult rv = QueryCache(aConn, aCacheId, aRequest, params, matches);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = DeleteEntries(aConn, matches, aDeletedBodyIdListOut);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = InsertEntry(aConn, aCacheId, aRequest, aRequestBodyId, aResponse,
                    aResponseBodyId);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
-                      const PCacheRequest& aRequest,
-                      const PCacheQueryParams& aParams,
-                      nsTArray<nsID>& aDeletedBodyIdListOut, bool* aSuccessOut)
+CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
+            const CacheRequest& aRequest,
+            const CacheQueryParams& aParams,
+            nsTArray<nsID>& aDeletedBodyIdListOut, bool* aSuccessOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   MOZ_ASSERT(aSuccessOut);
 
   *aSuccessOut = false;
 
   nsAutoTArray<EntryId, 256> matches;
@@ -530,29 +566,28 @@ DBSchema::CacheDelete(mozIStorageConnect
   rv = DeleteEntries(aConn, matches, aDeletedBodyIdListOut);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   *aSuccessOut = true;
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
-                    const PCacheRequestOrVoid& aRequestOrVoid,
-                    const PCacheQueryParams& aParams,
-                    nsTArray<SavedRequest>& aSavedRequestsOut)
+CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
+          const CacheRequestOrVoid& aRequestOrVoid,
+          const CacheQueryParams& aParams,
+          nsTArray<SavedRequest>& aSavedRequestsOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   nsresult rv;
 
   nsAutoTArray<EntryId, 256> matches;
-  if (aRequestOrVoid.type() == PCacheRequestOrVoid::Tvoid_t) {
+  if (aRequestOrVoid.type() == CacheRequestOrVoid::Tvoid_t) {
     rv = QueryAll(aConn, aCacheId, matches);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   } else {
     rv = QueryCache(aConn, aCacheId, aRequestOrVoid, aParams, matches);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   }
 
   // TODO: replace this with a bulk load using SQL IN clause (bug 1110458)
@@ -562,24 +597,23 @@ DBSchema::CacheKeys(mozIStorageConnectio
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     savedRequest.mCacheId = aCacheId;
     aSavedRequestsOut.AppendElement(savedRequest);
   }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::StorageMatch(mozIStorageConnection* aConn,
-                       Namespace aNamespace,
-                       const PCacheRequest& aRequest,
-                       const PCacheQueryParams& aParams,
-                       bool* aFoundResponseOut,
-                       SavedResponse* aSavedResponseOut)
+StorageMatch(mozIStorageConnection* aConn,
+             Namespace aNamespace,
+             const CacheRequest& aRequest,
+             const CacheQueryParams& aParams,
+             bool* aFoundResponseOut,
+             SavedResponse* aSavedResponseOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   MOZ_ASSERT(aFoundResponseOut);
   MOZ_ASSERT(aSavedResponseOut);
 
   *aFoundResponseOut = false;
 
@@ -634,21 +668,20 @@ DBSchema::StorageMatch(mozIStorageConnec
       aSavedResponseOut->mCacheId = cacheIdList[i];
       return rv;
     }
   }
 
   return NS_OK;
 }
 
-// static
 nsresult
-DBSchema::StorageGetCacheId(mozIStorageConnection* aConn, Namespace aNamespace,
-                            const nsAString& aKey, bool* aFoundCacheOut,
-                            CacheId* aCacheIdOut)
+StorageGetCacheId(mozIStorageConnection* aConn, Namespace aNamespace,
+                  const nsAString& aKey, bool* aFoundCacheOut,
+                  CacheId* aCacheIdOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   MOZ_ASSERT(aFoundCacheOut);
   MOZ_ASSERT(aCacheIdOut);
 
   *aFoundCacheOut = false;
 
@@ -674,20 +707,19 @@ DBSchema::StorageGetCacheId(mozIStorageC
 
   rv = state->GetInt64(0, aCacheIdOut);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   *aFoundCacheOut = true;
   return rv;
 }
 
-// static
 nsresult
-DBSchema::StoragePutCache(mozIStorageConnection* aConn, Namespace aNamespace,
-                          const nsAString& aKey, CacheId aCacheId)
+StoragePutCache(mozIStorageConnection* aConn, Namespace aNamespace,
+                const nsAString& aKey, CacheId aCacheId)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   nsCOMPtr<mozIStorageStatement> state;
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "INSERT INTO storage (namespace, key, cache_id) VALUES(?1, ?2, ?3);"
   ), getter_AddRefs(state));
@@ -703,20 +735,19 @@ DBSchema::StoragePutCache(mozIStorageCon
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->Execute();
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::StorageForgetCache(mozIStorageConnection* aConn, Namespace aNamespace,
-                             const nsAString& aKey)
+StorageForgetCache(mozIStorageConnection* aConn, Namespace aNamespace,
+                   const nsAString& aKey)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   nsCOMPtr<mozIStorageStatement> state;
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "DELETE FROM storage WHERE namespace=?1 AND key=?2;"
   ), getter_AddRefs(state));
@@ -729,20 +760,19 @@ DBSchema::StorageForgetCache(mozIStorage
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->Execute();
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::StorageGetKeys(mozIStorageConnection* aConn, Namespace aNamespace,
-                         nsTArray<nsString>& aKeysOut)
+StorageGetKeys(mozIStorageConnection* aConn, Namespace aNamespace,
+               nsTArray<nsString>& aKeysOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   nsCOMPtr<mozIStorageStatement> state;
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT key FROM storage WHERE namespace=?1 ORDER BY rowid;"
   ), getter_AddRefs(state));
@@ -757,20 +787,21 @@ DBSchema::StorageGetKeys(mozIStorageConn
     rv = state->GetString(0, key);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     aKeysOut.AppendElement(key);
   }
 
   return rv;
 }
 
-// static
+namespace {
+
 nsresult
-DBSchema::QueryAll(mozIStorageConnection* aConn, CacheId aCacheId,
-                   nsTArray<EntryId>& aEntryIdListOut)
+QueryAll(mozIStorageConnection* aConn, CacheId aCacheId,
+         nsTArray<EntryId>& aEntryIdListOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   nsCOMPtr<mozIStorageStatement> state;
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT id FROM entries WHERE cache_id=?1 ORDER BY id;"
   ), getter_AddRefs(state));
@@ -785,23 +816,22 @@ DBSchema::QueryAll(mozIStorageConnection
     rv = state->GetInt32(0, &entryId);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     aEntryIdListOut.AppendElement(entryId);
   }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::QueryCache(mozIStorageConnection* aConn, CacheId aCacheId,
-                     const PCacheRequest& aRequest,
-                     const PCacheQueryParams& aParams,
-                     nsTArray<EntryId>& aEntryIdListOut,
-                     uint32_t aMaxResults)
+QueryCache(mozIStorageConnection* aConn, CacheId aCacheId,
+           const CacheRequest& aRequest,
+           const CacheQueryParams& aParams,
+           nsTArray<EntryId>& aEntryIdListOut,
+           uint32_t aMaxResults)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   MOZ_ASSERT(aMaxResults > 0);
 
   if (!aParams.ignoreMethod() && !aRequest.method().LowerCaseEqualsLiteral("get")
                               && !aRequest.method().LowerCaseEqualsLiteral("head"))
   {
@@ -863,21 +893,20 @@ DBSchema::QueryCache(mozIStorageConnecti
     if (aEntryIdListOut.Length() == aMaxResults) {
       return NS_OK;
     }
   }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::MatchByVaryHeader(mozIStorageConnection* aConn,
-                            const PCacheRequest& aRequest,
-                            EntryId entryId, bool* aSuccessOut)
+MatchByVaryHeader(mozIStorageConnection* aConn,
+                  const CacheRequest& aRequest,
+                  EntryId entryId, bool* aSuccessOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   *aSuccessOut = false;
 
   nsCOMPtr<mozIStorageStatement> state;
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
@@ -908,34 +937,36 @@ DBSchema::MatchByVaryHeader(mozIStorageC
     "SELECT name, value FROM request_headers "
     "WHERE entry_id=?1;"
   ), getter_AddRefs(state));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->BindInt32Parameter(0, entryId);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
-  nsRefPtr<InternalHeaders> cachedHeaders = new InternalHeaders(HeadersGuardEnum::None);
+  nsRefPtr<InternalHeaders> cachedHeaders =
+    new InternalHeaders(HeadersGuardEnum::None);
 
   while (NS_SUCCEEDED(state->ExecuteStep(&hasMoreData)) && hasMoreData) {
     nsAutoCString name;
     nsAutoCString value;
     rv = state->GetUTF8String(0, name);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     rv = state->GetUTF8String(1, value);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     ErrorResult errorResult;
 
     cachedHeaders->Append(name, value, errorResult);
     if (errorResult.Failed()) { return errorResult.ErrorCode(); };
   }
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
-  nsRefPtr<InternalHeaders> queryHeaders = new InternalHeaders(aRequest.headers());
+  nsRefPtr<InternalHeaders> queryHeaders =
+    TypeUtils::ToInternalHeaders(aRequest.headers());
 
   // Assume the vary headers match until we find a conflict
   bool varyHeadersMatch = true;
 
   for (uint32_t i = 0; i < varyValues.Length(); ++i) {
     // Extract the header names inside the Vary header value.
     nsAutoCString varyValue(varyValues[i]);
     char* rawBuffer = varyValue.BeginWriting();
@@ -974,22 +1005,21 @@ DBSchema::MatchByVaryHeader(mozIStorageC
       break;
     }
   }
 
   *aSuccessOut = varyHeadersMatch;
   return rv;
 }
 
-// static
 nsresult
-DBSchema::DeleteEntries(mozIStorageConnection* aConn,
-                        const nsTArray<EntryId>& aEntryIdList,
-                        nsTArray<nsID>& aDeletedBodyIdListOut,
-                        uint32_t aPos, int32_t aLen)
+DeleteEntries(mozIStorageConnection* aConn,
+              const nsTArray<EntryId>& aEntryIdList,
+              nsTArray<nsID>& aDeletedBodyIdListOut,
+              uint32_t aPos, int32_t aLen)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   if (aEntryIdList.IsEmpty()) {
     return NS_OK;
   }
 
@@ -1063,23 +1093,22 @@ DBSchema::DeleteEntries(mozIStorageConne
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->Execute();
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
-                      const PCacheRequest& aRequest,
-                      const nsID* aRequestBodyId,
-                      const PCacheResponse& aResponse,
-                      const nsID* aResponseBodyId)
+InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
+            const CacheRequest& aRequest,
+            const nsID* aRequestBodyId,
+            const CacheResponse& aResponse,
+            const nsID* aResponseBodyId)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
 
   nsCOMPtr<mozIStorageStatement> state;
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "INSERT INTO entries ("
       "request_method, "
@@ -1190,17 +1219,17 @@ DBSchema::InsertEntry(mozIStorageConnect
     "INSERT INTO request_headers ("
       "name, "
       "value, "
       "entry_id "
     ") VALUES (?1, ?2, ?3)"
   ), getter_AddRefs(state));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
-  const nsTArray<PHeadersEntry>& requestHeaders = aRequest.headers();
+  const nsTArray<HeadersEntry>& requestHeaders = aRequest.headers();
   for (uint32_t i = 0; i < requestHeaders.Length(); ++i) {
     rv = state->BindUTF8StringParameter(0, requestHeaders[i].name());
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = state->BindUTF8StringParameter(1, requestHeaders[i].value());
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = state->BindInt32Parameter(2, entryId);
@@ -1214,17 +1243,17 @@ DBSchema::InsertEntry(mozIStorageConnect
     "INSERT INTO response_headers ("
       "name, "
       "value, "
       "entry_id "
     ") VALUES (?1, ?2, ?3)"
   ), getter_AddRefs(state));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
-  const nsTArray<PHeadersEntry>& responseHeaders = aResponse.headers();
+  const nsTArray<HeadersEntry>& responseHeaders = aResponse.headers();
   for (uint32_t i = 0; i < responseHeaders.Length(); ++i) {
     rv = state->BindUTF8StringParameter(0, responseHeaders[i].name());
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = state->BindUTF8StringParameter(1, responseHeaders[i].value());
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = state->BindInt32Parameter(2, entryId);
@@ -1232,20 +1261,19 @@ DBSchema::InsertEntry(mozIStorageConnect
 
     rv = state->Execute();
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
-                       SavedResponse* aSavedResponseOut)
+ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
+             SavedResponse* aSavedResponseOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   MOZ_ASSERT(aSavedResponseOut);
 
   nsCOMPtr<mozIStorageStatement> state;
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT "
@@ -1315,34 +1343,33 @@ DBSchema::ReadResponse(mozIStorageConnec
     "WHERE entry_id=?1;"
   ), getter_AddRefs(state));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->BindInt32Parameter(0, aEntryId);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   while (NS_SUCCEEDED(state->ExecuteStep(&hasMoreData)) && hasMoreData) {
-    PHeadersEntry header;
+    HeadersEntry header;
 
     rv = state->GetUTF8String(0, header.name());
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = state->GetUTF8String(1, header.value());
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     aSavedResponseOut->mValue.headers().AppendElement(header);
   }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
-                      SavedRequest* aSavedRequestOut)
+ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
+            SavedRequest* aSavedRequestOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aConn);
   MOZ_ASSERT(aSavedRequestOut);
 
   nsCOMPtr<mozIStorageStatement> state;
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT "
@@ -1434,65 +1461,62 @@ DBSchema::ReadRequest(mozIStorageConnect
     "WHERE entry_id=?1;"
   ), getter_AddRefs(state));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->BindInt32Parameter(0, aEntryId);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   while (NS_SUCCEEDED(state->ExecuteStep(&hasMoreData)) && hasMoreData) {
-    PHeadersEntry header;
+    HeadersEntry header;
 
     rv = state->GetUTF8String(0, header.name());
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = state->GetUTF8String(1, header.value());
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     aSavedRequestOut->mValue.headers().AppendElement(header);
   }
 
   return rv;
 }
 
-// static
 void
-DBSchema::AppendListParamsToQuery(nsACString& aQuery,
-                                  const nsTArray<EntryId>& aEntryIdList,
-                                  uint32_t aPos, int32_t aLen)
+AppendListParamsToQuery(nsACString& aQuery,
+                        const nsTArray<EntryId>& aEntryIdList,
+                        uint32_t aPos, int32_t aLen)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT((aPos + aLen) <= aEntryIdList.Length());
   for (int32_t i = aPos; i < aLen; ++i) {
     if (i == 0) {
       aQuery.AppendLiteral("?");
     } else {
       aQuery.AppendLiteral(",?");
     }
   }
 }
 
-// static
 nsresult
-DBSchema::BindListParamsToQuery(mozIStorageStatement* aState,
-                                const nsTArray<EntryId>& aEntryIdList,
-                                uint32_t aPos, int32_t aLen)
+BindListParamsToQuery(mozIStorageStatement* aState,
+                      const nsTArray<EntryId>& aEntryIdList,
+                      uint32_t aPos, int32_t aLen)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT((aPos + aLen) <= aEntryIdList.Length());
   for (int32_t i = aPos; i < aLen; ++i) {
     nsresult rv = aState->BindInt32Parameter(i, aEntryIdList[i]);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
-// static
 nsresult
-DBSchema::BindId(mozIStorageStatement* aState, uint32_t aPos, const nsID* aId)
+BindId(mozIStorageStatement* aState, uint32_t aPos, const nsID* aId)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aState);
   nsresult rv;
 
   if (!aId) {
     rv = aState->BindNullParameter(aPos);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -1502,29 +1526,31 @@ DBSchema::BindId(mozIStorageStatement* a
   char idBuf[NSID_LENGTH];
   aId->ToProvidedString(idBuf);
   rv = aState->BindUTF8StringParameter(aPos, nsAutoCString(idBuf));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
-// static
 nsresult
-DBSchema::ExtractId(mozIStorageStatement* aState, uint32_t aPos, nsID* aIdOut)
+ExtractId(mozIStorageStatement* aState, uint32_t aPos, nsID* aIdOut)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(aState);
   MOZ_ASSERT(aIdOut);
 
   nsAutoCString idString;
   nsresult rv = aState->GetUTF8String(aPos, idString);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   bool success = aIdOut->Parse(idString.get());
   if (NS_WARN_IF(!success)) { return NS_ERROR_UNEXPECTED; }
 
   return rv;
 }
 
+} // anonymouns namespace
+
+} // namespace db
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/DBSchema.h
+++ b/dom/cache/DBSchema.h
@@ -9,136 +9,107 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/cache/Types.h"
 #include "nsError.h"
 #include "nsString.h"
 #include "nsTArrayForwardDeclare.h"
 
 class mozIStorageConnection;
-class mozIStorageStatement;
 struct nsID;
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
-class PCacheQueryParams;
-class PCacheRequest;
-class PCacheRequestOrVoid;
-class PCacheResponse;
+class CacheQueryParams;
+class CacheRequest;
+class CacheRequestOrVoid;
+class CacheResponse;
 struct SavedRequest;
 struct SavedResponse;
 
-// TODO: remove static class and use functions in cache namespace (bug 1110485)
-class DBSchema final
-{
-public:
-  static nsresult CreateSchema(mozIStorageConnection* aConn);
-  static nsresult InitializeConnection(mozIStorageConnection* aConn);
+namespace db {
+
+nsresult
+CreateSchema(mozIStorageConnection* aConn);
 
-  static nsresult CreateCache(mozIStorageConnection* aConn,
-                              CacheId* aCacheIdOut);
-  // TODO: improve naming (confusing with CacheDelete) (bug 1110485)
-  static nsresult DeleteCache(mozIStorageConnection* aConn, CacheId aCacheId,
-                              nsTArray<nsID>& aDeletedBodyIdListOut);
+nsresult
+InitializeConnection(mozIStorageConnection* aConn);
 
-  // TODO: Consider removing unused IsCacheOrphaned after writing cleanup code. (bug 1110446)
-  static nsresult IsCacheOrphaned(mozIStorageConnection* aConn,
-                                  CacheId aCacheId, bool* aOrphanedOut);
+nsresult
+CreateCacheId(mozIStorageConnection* aConn, CacheId* aCacheIdOut);
+
+nsresult
+DeleteCacheId(mozIStorageConnection* aConn, CacheId aCacheId,
+              nsTArray<nsID>& aDeletedBodyIdListOut);
 
-  static nsresult CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
-                             const PCacheRequest& aRequest,
-                             const PCacheQueryParams& aParams,
-                             bool* aFoundResponseOut,
-                             SavedResponse* aSavedResponseOut);
-  static nsresult CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
-                                const PCacheRequestOrVoid& aRequestOrVoid,
-                                const PCacheQueryParams& aParams,
-                                nsTArray<SavedResponse>& aSavedResponsesOut);
-  static nsresult CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
-                           const PCacheRequest& aRequest,
-                           const nsID* aRequestBodyId,
-                           const PCacheResponse& aResponse,
-                           const nsID* aResponseBodyId,
-                           nsTArray<nsID>& aDeletedBodyIdListOut);
-  static nsresult CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
-                              const PCacheRequest& aRequest,
-                              const PCacheQueryParams& aParams,
-                              nsTArray<nsID>& aDeletedBodyIdListOut,
-                              bool* aSuccessOut);
-  static nsresult CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
-                            const PCacheRequestOrVoid& aRequestOrVoid,
-                            const PCacheQueryParams& aParams,
-                            nsTArray<SavedRequest>& aSavedRequestsOut);
+// TODO: Consider removing unused IsCacheOrphaned after writing cleanup code. (bug 1110446)
+nsresult
+IsCacheOrphaned(mozIStorageConnection* aConn, CacheId aCacheId,
+                bool* aOrphanedOut);
+
+nsresult
+CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
+           const CacheRequest& aRequest, const CacheQueryParams& aParams,
+           bool* aFoundResponseOut, SavedResponse* aSavedResponseOut);
+
+nsresult
+CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
+              const CacheRequestOrVoid& aRequestOrVoid,
+              const CacheQueryParams& aParams,
+              nsTArray<SavedResponse>& aSavedResponsesOut);
+
+nsresult
+CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
+         const CacheRequest& aRequest,
+         const nsID* aRequestBodyId,
+         const CacheResponse& aResponse,
+         const nsID* aResponseBodyId,
+         nsTArray<nsID>& aDeletedBodyIdListOut);
 
-  static nsresult StorageMatch(mozIStorageConnection* aConn,
-                               Namespace aNamespace,
-                               const PCacheRequest& aRequest,
-                               const PCacheQueryParams& aParams,
-                               bool* aFoundResponseOut,
-                               SavedResponse* aSavedResponseOut);
-  static nsresult StorageGetCacheId(mozIStorageConnection* aConn,
-                                    Namespace aNamespace, const nsAString& aKey,
-                                    bool* aFoundCacheOut, CacheId* aCacheIdOut);
-  static nsresult StoragePutCache(mozIStorageConnection* aConn,
-                                  Namespace aNamespace, const nsAString& aKey,
-                                  CacheId aCacheId);
-  static nsresult StorageForgetCache(mozIStorageConnection* aConn,
-                                     Namespace aNamespace,
-                                     const nsAString& aKey);
-  static nsresult StorageGetKeys(mozIStorageConnection* aConn,
-                                 Namespace aNamespace,
-                                 nsTArray<nsString>& aKeysOut);
+nsresult
+CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
+            const CacheRequest& aRequest,
+            const CacheQueryParams& aParams,
+            nsTArray<nsID>& aDeletedBodyIdListOut,
+            bool* aSuccessOut);
 
-  // We will wipe out databases with a schema versions less than this.
-  static const int32_t kMaxWipeSchemaVersion;
+nsresult
+CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
+          const CacheRequestOrVoid& aRequestOrVoid,
+          const CacheQueryParams& aParams,
+          nsTArray<SavedRequest>& aSavedRequestsOut);
 
-private:
-  typedef int32_t EntryId;
+nsresult
+StorageMatch(mozIStorageConnection* aConn,
+             Namespace aNamespace,
+             const CacheRequest& aRequest,
+             const CacheQueryParams& aParams,
+             bool* aFoundResponseOut,
+             SavedResponse* aSavedResponseOut);
 
-  static nsresult QueryAll(mozIStorageConnection* aConn, CacheId aCacheId,
-                           nsTArray<EntryId>& aEntryIdListOut);
-  static nsresult QueryCache(mozIStorageConnection* aConn, CacheId aCacheId,
-                             const PCacheRequest& aRequest,
-                             const PCacheQueryParams& aParams,
-                             nsTArray<EntryId>& aEntryIdListOut,
-                             uint32_t aMaxResults = UINT32_MAX);
-  static nsresult MatchByVaryHeader(mozIStorageConnection* aConn,
-                                    const PCacheRequest& aRequest,
-                                    EntryId entryId, bool* aSuccessOut);
-  static nsresult DeleteEntries(mozIStorageConnection* aConn,
-                                const nsTArray<EntryId>& aEntryIdList,
-                                nsTArray<nsID>& aDeletedBodyIdListOut,
-                                uint32_t aPos=0, int32_t aLen=-1);
-  static nsresult InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
-                              const PCacheRequest& aRequest,
-                              const nsID* aRequestBodyId,
-                              const PCacheResponse& aResponse,
-                              const nsID* aResponseBodyId);
-  static nsresult ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
-                               SavedResponse* aSavedResponseOut);
-  static nsresult ReadRequest(mozIStorageConnection* aConn, EntryId aEntryId,
-                              SavedRequest* aSavedRequestOut);
+nsresult
+StorageGetCacheId(mozIStorageConnection* aConn, Namespace aNamespace,
+                  const nsAString& aKey, bool* aFoundCacheOut,
+                  CacheId* aCacheIdOut);
+
+nsresult
+StoragePutCache(mozIStorageConnection* aConn, Namespace aNamespace,
+                const nsAString& aKey, CacheId aCacheId);
 
-  static void AppendListParamsToQuery(nsACString& aQuery,
-                                      const nsTArray<EntryId>& aEntryIdList,
-                                      uint32_t aPos, int32_t aLen);
-  static nsresult BindListParamsToQuery(mozIStorageStatement* aState,
-                                        const nsTArray<EntryId>& aEntryIdList,
-                                        uint32_t aPos, int32_t aLen);
-  static nsresult BindId(mozIStorageStatement* aState, uint32_t aPos,
-                         const nsID* aId);
-  static nsresult ExtractId(mozIStorageStatement* aState, uint32_t aPos,
-                            nsID* aIdOut);
+nsresult
+StorageForgetCache(mozIStorageConnection* aConn, Namespace aNamespace,
+                   const nsAString& aKey);
 
-  DBSchema() = delete;
-  ~DBSchema() = delete;
+nsresult
+StorageGetKeys(mozIStorageConnection* aConn, Namespace aNamespace,
+               nsTArray<nsString>& aKeysOut);
 
-  static const int32_t kLatestSchemaVersion;
-  static const int32_t kMaxEntriesPerStatement;
-};
+// We will wipe out databases with a schema versions less than this.
+extern const int32_t kMaxWipeSchemaVersion;
 
+} // namespace db
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_cache_DBSchema_h
--- a/dom/cache/FetchPut.cpp
+++ b/dom/cache/FetchPut.cpp
@@ -11,17 +11,16 @@
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/ResponseBinding.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/cache/ManagerId.h"
-#include "mozilla/dom/cache/PCacheTypes.h"
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 #include "nsCRT.h"
 #include "nsHttp.h"
 
 namespace mozilla {
 namespace dom {
@@ -93,34 +92,33 @@ protected:
 
 private:
   nsRefPtr<FetchPut> mFetchPut;
   nsRefPtr<InternalResponse> mInternalResponse;
 };
 
 // static
 nsresult
-FetchPut::Create(Listener* aListener, Manager* aManager,
-                 RequestId aRequestId, CacheId aCacheId,
-                 const nsTArray<PCacheRequest>& aRequests,
+FetchPut::Create(Listener* aListener, Manager* aManager, CacheId aCacheId,
+                 const nsTArray<CacheRequest>& aRequests,
                  const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams,
                  FetchPut** aFetchPutOut)
 {
   MOZ_ASSERT(aRequests.Length() == aRequestStreams.Length());
 
   // The FetchDriver requires that all requests have a referrer already set.
 #ifdef DEBUG
   for (uint32_t i = 0; i < aRequests.Length(); ++i) {
     if (aRequests[i].referrer() == EmptyString()) {
       return NS_ERROR_UNEXPECTED;
     }
   }
 #endif
 
-  nsRefPtr<FetchPut> ref = new FetchPut(aListener, aManager, aRequestId, aCacheId,
+  nsRefPtr<FetchPut> ref = new FetchPut(aListener, aManager, aCacheId,
                                         aRequests, aRequestStreams);
 
   nsresult rv = ref->DispatchToMainThread();
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   ref.forget(aFetchPutOut);
 
   return NS_OK;
@@ -128,35 +126,33 @@ FetchPut::Create(Listener* aListener, Ma
 
 void
 FetchPut::ClearListener()
 {
   MOZ_ASSERT(mListener);
   mListener = nullptr;
 }
 
-FetchPut::FetchPut(Listener* aListener, Manager* aManager,
-                   RequestId aRequestId, CacheId aCacheId,
-                   const nsTArray<PCacheRequest>& aRequests,
+FetchPut::FetchPut(Listener* aListener, Manager* aManager, CacheId aCacheId,
+                   const nsTArray<CacheRequest>& aRequests,
                    const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams)
   : mListener(aListener)
   , mManager(aManager)
-  , mRequestId(aRequestId)
   , mCacheId(aCacheId)
   , mInitiatingThread(NS_GetCurrentThread())
   , mStateList(aRequests.Length())
   , mPendingCount(0)
 {
   MOZ_ASSERT(mListener);
   MOZ_ASSERT(mManager);
   MOZ_ASSERT(aRequests.Length() == aRequestStreams.Length());
 
   for (uint32_t i = 0; i < aRequests.Length(); ++i) {
     State* s = mStateList.AppendElement();
-    s->mPCacheRequest = aRequests[i];
+    s->mCacheRequest = aRequests[i];
     s->mRequestStream = aRequestStreams[i];
   }
 
   mManager->AddRefCacheId(mCacheId);
 }
 
 FetchPut::~FetchPut()
 {
@@ -206,24 +202,24 @@ FetchPut::DoFetchOnMainThread()
 
   nsRefPtr<ManagerId> managerId = mManager->GetManagerId();
   nsCOMPtr<nsIPrincipal> principal = managerId->Principal();
   mPendingCount = mStateList.Length();
 
   nsCOMPtr<nsILoadGroup> loadGroup;
   nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    MaybeSetError(rv);
+    MaybeSetError(ErrorResult(rv));
     MaybeCompleteOnMainThread();
     return;
   }
 
   for (uint32_t i = 0; i < mStateList.Length(); ++i) {
     nsRefPtr<InternalRequest> internalRequest =
-      ToInternalRequest(mStateList[i].mPCacheRequest);
+      ToInternalRequest(mStateList[i].mCacheRequest);
 
     // If there is a stream we must clone it so that its still available
     // to store in the cache later;
     if (mStateList[i].mRequestStream) {
       internalRequest->SetBody(mStateList[i].mRequestStream);
       nsRefPtr<InternalRequest> clone = internalRequest->Clone();
 
       // The copy construction clone above can change the source stream,
@@ -235,17 +231,17 @@ FetchPut::DoFetchOnMainThread()
 
     nsRefPtr<FetchDriver> fetchDriver = new FetchDriver(internalRequest,
                                                         principal,
                                                         loadGroup);
 
     mStateList[i].mFetchObserver = new FetchObserver(this);
     rv = fetchDriver->Fetch(mStateList[i].mFetchObserver);
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      MaybeSetError(rv);
+      MaybeSetError(ErrorResult(rv));
       mStateList[i].mFetchObserver = nullptr;
       mPendingCount -= 1;
       continue;
     }
   }
 
   // If they all failed, then we might need to complete main thread immediately
   MaybeCompleteOnMainThread();
@@ -253,26 +249,26 @@ FetchPut::DoFetchOnMainThread()
 
 void
 FetchPut::FetchComplete(FetchObserver* aObserver,
                         InternalResponse* aInternalResponse)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (aInternalResponse->IsError() && !mResult.Failed()) {
-    MaybeSetError(NS_ERROR_FAILURE);
+    MaybeSetError(ErrorResult(NS_ERROR_FAILURE));
   }
 
   for (uint32_t i = 0; i < mStateList.Length(); ++i) {
     if (mStateList[i].mFetchObserver == aObserver) {
       ErrorResult rv;
-      ToPCacheResponseWithoutBody(mStateList[i].mPCacheResponse,
+      ToCacheResponseWithoutBody(mStateList[i].mCacheResponse,
                                   *aInternalResponse, rv);
       if (rv.Failed()) {
-        mResult = Move(rv);
+        MaybeSetError(Move(rv));
       } else {
         aInternalResponse->GetBody(getter_AddRefs(mStateList[i].mResponseStream));
       }
       mStateList[i].mFetchObserver = nullptr;
       MOZ_ASSERT(mPendingCount > 0);
       mPendingCount -= 1;
       MaybeCompleteOnMainThread();
       return;
@@ -311,67 +307,67 @@ FetchPut::DoPutOnWorkerThread()
 
   putList.SetCapacity(mStateList.Length());
   requestStreamList.SetCapacity(mStateList.Length());
   responseStreamList.SetCapacity(mStateList.Length());
 
   for (uint32_t i = 0; i < mStateList.Length(); ++i) {
     // The spec requires us to catch if content tries to insert a set of
     // requests that would overwrite each other.
-    if (MatchInPutList(mStateList[i].mPCacheRequest, putList)) {
-      MaybeSetError(NS_ERROR_DOM_INVALID_STATE_ERR);
+    if (MatchInPutList(mStateList[i].mCacheRequest, putList)) {
+      MaybeSetError(ErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
       MaybeNotifyListener();
       return;
     }
 
     CacheRequestResponse* entry = putList.AppendElement();
-    entry->request() = mStateList[i].mPCacheRequest;
-    entry->response() = mStateList[i].mPCacheResponse;
+    entry->request() = mStateList[i].mCacheRequest;
+    entry->response() = mStateList[i].mCacheResponse;
     requestStreamList.AppendElement(mStateList[i].mRequestStream.forget());
     responseStreamList.AppendElement(mStateList[i].mResponseStream.forget());
   }
   mStateList.Clear();
 
-  mManager->CachePutAll(this, mRequestId, mCacheId, putList, requestStreamList,
-                        responseStreamList);
+  mManager->ExecutePutAll(this, mCacheId, putList, requestStreamList,
+                          responseStreamList);
 }
 
 // static
 bool
-FetchPut::MatchInPutList(const PCacheRequest& aRequest,
+FetchPut::MatchInPutList(const CacheRequest& aRequest,
                          const nsTArray<CacheRequestResponse>& aPutList)
 {
   // This method implements the SW spec QueryCache algorithm against an
   // in memory array of Request/Response objects.  This essentially the
   // same algorithm that is implemented in DBSchema.cpp.  Unfortunately
   // we cannot unify them because when operating against the real database
   // we don't want to load all request/response objects into memory.
 
   if (!aRequest.method().LowerCaseEqualsLiteral("get") &&
       !aRequest.method().LowerCaseEqualsLiteral("head")) {
     return false;
   }
 
   nsRefPtr<InternalHeaders> requestHeaders =
-    new InternalHeaders(aRequest.headers());
+    ToInternalHeaders(aRequest.headers());
 
   for (uint32_t i = 0; i < aPutList.Length(); ++i) {
-    const PCacheRequest& cachedRequest = aPutList[i].request();
-    const PCacheResponse& cachedResponse = aPutList[i].response();
+    const CacheRequest& cachedRequest = aPutList[i].request();
+    const CacheResponse& cachedResponse = aPutList[i].response();
 
     // If the URLs don't match, then just skip to the next entry.
     if (aRequest.url() != cachedRequest.url()) {
       continue;
     }
 
     nsRefPtr<InternalHeaders> cachedRequestHeaders =
-      new InternalHeaders(cachedRequest.headers());
+      ToInternalHeaders(cachedRequest.headers());
 
     nsRefPtr<InternalHeaders> cachedResponseHeaders =
-      new InternalHeaders(cachedResponse.headers());
+      ToInternalHeaders(cachedResponse.headers());
 
     nsAutoTArray<nsCString, 16> varyHeaders;
     ErrorResult rv;
     cachedResponseHeaders->GetAll(NS_LITERAL_CSTRING("vary"), varyHeaders, rv);
     MOZ_ALWAYS_TRUE(!rv.Failed());
 
     // Assume the vary headers match until we find a conflict
     bool varyHeadersMatch = true;
@@ -421,45 +417,49 @@ FetchPut::MatchInPutList(const PCacheReq
       return true;
     }
   }
 
   return false;
 }
 
 void
-FetchPut::OnCachePutAll(RequestId aRequestId, nsresult aRv)
+FetchPut::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
+                       CacheId aOpenedCacheId,
+                       const nsTArray<SavedResponse>& aSavedResponseList,
+                       const nsTArray<SavedRequest>& aSavedRequestList,
+                       StreamList* aStreamList)
 {
   MOZ_ASSERT(mInitiatingThread == NS_GetCurrentThread());
-  MaybeSetError(aRv);
+  MOZ_ASSERT(aResult.type() == CacheOpResult::TCachePutAllResult);
+  MaybeSetError(Move(aRv));
   MaybeNotifyListener();
 }
 
 void
-FetchPut::MaybeSetError(nsresult aRv)
+FetchPut::MaybeSetError(ErrorResult&& aRv)
 {
-  if (mResult.Failed() || NS_SUCCEEDED(aRv)) {
+  if (mResult.Failed() || !aRv.Failed()) {
     return;
   }
-  mResult.Throw(aRv);
+  mResult = Move(aRv);
 }
 
 void
 FetchPut::MaybeNotifyListener()
 {
   MOZ_ASSERT(mInitiatingThread == NS_GetCurrentThread());
   if (!mListener) {
     return;
   }
   // CacheParent::OnFetchPut can lead to the destruction of |this| when the
   // object is removed from CacheParent::mFetchPutList, so make sure that
   // doesn't happen until this method returns.
   nsRefPtr<FetchPut> kungFuDeathGrip(this);
-  mListener->OnFetchPut(this, mRequestId, mResult);
-  mResult.ClearMessage(); // This may contain a TypeError.
+  mListener->OnFetchPut(this, Move(mResult));
 }
 
 nsIGlobalObject*
 FetchPut::GetGlobalObject() const
 {
   MOZ_CRASH("No global object in parent-size FetchPut operation!");
 }
 
--- a/dom/cache/FetchPut.h
+++ b/dom/cache/FetchPut.h
@@ -6,17 +6,17 @@
 
 #ifndef mozilla_dom_cache_FetchPut_h
 #define mozilla_dom_cache_FetchPut_h
 
 #include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/cache/Manager.h"
-#include "mozilla/dom/cache/PCacheTypes.h"
+#include "mozilla/dom/cache/CacheTypes.h"
 #include "mozilla/dom/cache/Types.h"
 #include "mozilla/dom/cache/TypeUtils.h"
 #include "nsRefPtr.h"
 #include "nsTArray.h"
 #include <utility>
 
 class nsIInputStream;
 class nsIRunnable;
@@ -35,78 +35,81 @@ class FetchPut final : public Manager::L
 {
 public:
   typedef std::pair<nsRefPtr<Request>, nsRefPtr<Response>> PutPair;
 
   class Listener
   {
   public:
     virtual void
-    OnFetchPut(FetchPut* aFetchPut, RequestId aRequestId, const ErrorResult& aRv) = 0;
+    OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv) = 0;
   };
 
   static nsresult
-  Create(Listener* aListener, Manager* aManager,
-         RequestId aRequestId, CacheId aCacheId,
-         const nsTArray<PCacheRequest>& aRequests,
+  Create(Listener* aListener, Manager* aManager, CacheId aCacheId,
+         const nsTArray<CacheRequest>& aRequests,
          const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams,
          FetchPut** aFetchPutOut);
 
   void ClearListener();
 
 private:
   class Runnable;
   class FetchObserver;
   friend class FetchObserver;
   struct State
   {
-    PCacheRequest mPCacheRequest;
+    CacheRequest mCacheRequest;
     nsCOMPtr<nsIInputStream> mRequestStream;
     nsRefPtr<FetchObserver> mFetchObserver;
-    PCacheResponse mPCacheResponse;
+    CacheResponse mCacheResponse;
     nsCOMPtr<nsIInputStream> mResponseStream;
 
     nsRefPtr<Request> mRequest;
     nsRefPtr<Response> mResponse;
   };
 
-  FetchPut(Listener* aListener, Manager* aManager,
-           RequestId aRequestId, CacheId aCacheId,
-           const nsTArray<PCacheRequest>& aRequests,
+  FetchPut(Listener* aListener, Manager* aManager, CacheId aCacheId,
+           const nsTArray<CacheRequest>& aRequests,
            const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams);
   ~FetchPut();
 
   nsresult DispatchToMainThread();
   void DispatchToInitiatingThread();
 
   void DoFetchOnMainThread();
   void FetchComplete(FetchObserver* aObserver,
                      InternalResponse* aInternalResponse);
   void MaybeCompleteOnMainThread();
 
   void DoPutOnWorkerThread();
-  static bool MatchInPutList(const PCacheRequest& aRequest,
+  static bool MatchInPutList(const CacheRequest& aRequest,
                              const nsTArray<CacheRequestResponse>& aPutList);
-  virtual void OnCachePutAll(RequestId aRequestId, nsresult aRv) override;
 
-  void MaybeSetError(nsresult aRv);
+  virtual void
+  OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
+               CacheId aOpenedCacheId,
+               const nsTArray<SavedResponse>& aSavedResponseList,
+               const nsTArray<SavedRequest>& aSavedRequestList,
+               StreamList* aStreamList) override;
+
+  void MaybeSetError(ErrorResult&& aRv);
   void MaybeNotifyListener();
 
   // TypeUtils methods
   virtual nsIGlobalObject* GetGlobalObject() const override;
 #ifdef DEBUG
   virtual void AssertOwningThread() const override;
 #endif
 
   virtual CachePushStreamChild*
   CreatePushStream(nsIAsyncInputStream* aStream) override;
 
   Listener* mListener;
   nsRefPtr<Manager> mManager;
-  const RequestId mRequestId;
   const CacheId mCacheId;
   nsCOMPtr<nsIThread> mInitiatingThread;
   nsTArray<State> mStateList;
   uint32_t mPendingCount;
   ErrorResult mResult;
   nsCOMPtr<nsIRunnable> mRunnable;
 
 public:
--- a/dom/cache/FileUtils.cpp
+++ b/dom/cache/FileUtils.cpp
@@ -18,21 +18,34 @@
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 using mozilla::dom::quota::FileInputStream;
 using mozilla::dom::quota::FileOutputStream;
 using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
-using mozilla::unused;
+
+namespace {
+
+enum BodyFileType
+{
+  BODY_FILE_FINAL,
+  BODY_FILE_TMP
+};
+
+nsresult
+BodyIdToFile(nsIFile* aBaseDir, const nsID& aId, BodyFileType aType,
+             nsIFile** aBodyFileOut);
+
+} // anonymous namespace
 
 // static
 nsresult
-FileUtils::BodyCreateDir(nsIFile* aBaseDir)
+BodyCreateDir(nsIFile* aBaseDir)
 {
   MOZ_ASSERT(aBaseDir);
 
   nsCOMPtr<nsIFile> aBodyDir;
   nsresult rv = aBaseDir->Clone(getter_AddRefs(aBodyDir));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = aBodyDir->Append(NS_LITERAL_STRING("morgue"));
@@ -44,17 +57,17 @@ FileUtils::BodyCreateDir(nsIFile* aBaseD
   }
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
 // static
 nsresult
-FileUtils::BodyDeleteDir(nsIFile* aBaseDir)
+BodyDeleteDir(nsIFile* aBaseDir)
 {
   MOZ_ASSERT(aBaseDir);
 
   nsCOMPtr<nsIFile> aBodyDir;
   nsresult rv = aBaseDir->Clone(getter_AddRefs(aBodyDir));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = aBodyDir->Append(NS_LITERAL_STRING("morgue"));
@@ -67,18 +80,17 @@ FileUtils::BodyDeleteDir(nsIFile* aBaseD
   }
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
 // static
 nsresult
-FileUtils::BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId,
-                           nsIFile** aCacheDirOut)
+BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId, nsIFile** aCacheDirOut)
 {
   MOZ_ASSERT(aBaseDir);
   MOZ_ASSERT(aCacheDirOut);
 
   *aCacheDirOut = nullptr;
 
   nsresult rv = aBaseDir->Clone(aCacheDirOut);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -102,21 +114,21 @@ FileUtils::BodyGetCacheDir(nsIFile* aBas
   }
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
 // static
 nsresult
-FileUtils::BodyStartWriteStream(const QuotaInfo& aQuotaInfo,
-                                nsIFile* aBaseDir, nsIInputStream* aSource,
-                                void* aClosure,
-                                nsAsyncCopyCallbackFun aCallback, nsID* aIdOut,
-                                nsISupports** aCopyContextOut)
+BodyStartWriteStream(const QuotaInfo& aQuotaInfo,
+                     nsIFile* aBaseDir, nsIInputStream* aSource,
+                     void* aClosure,
+                     nsAsyncCopyCallbackFun aCallback, nsID* aIdOut,
+                     nsISupports** aCopyContextOut)
 {
   MOZ_ASSERT(aBaseDir);
   MOZ_ASSERT(aSource);
   MOZ_ASSERT(aClosure);
   MOZ_ASSERT(aCallback);
   MOZ_ASSERT(aIdOut);
   MOZ_ASSERT(aCopyContextOut);
 
@@ -163,31 +175,31 @@ FileUtils::BodyStartWriteStream(const Qu
                     aCopyContextOut);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
 // static
 void
-FileUtils::BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext)
+BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext)
 {
   MOZ_ASSERT(aBaseDir);
   MOZ_ASSERT(aCopyContext);
 
   nsresult rv = NS_CancelAsyncCopy(aCopyContext, NS_ERROR_ABORT);
   unused << NS_WARN_IF(NS_FAILED(rv));
 
   // The partially written file must be cleaned up after the async copy
   // makes its callback.
 }
 
 // static
 nsresult
-FileUtils::BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId)
+BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId)
 {
   MOZ_ASSERT(aBaseDir);
 
   nsCOMPtr<nsIFile> tmpFile;
   nsresult rv = BodyIdToFile(aBaseDir, aId, BODY_FILE_TMP, getter_AddRefs(tmpFile));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   nsCOMPtr<nsIFile> finalFile;
@@ -201,18 +213,18 @@ FileUtils::BodyFinalizeWrite(nsIFile* aB
   rv = tmpFile->RenameTo(nullptr, finalFileName);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
 // static
 nsresult
-FileUtils::BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
-                    const nsID& aId, nsIInputStream** aStreamOut)
+BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, const nsID& aId,
+         nsIInputStream** aStreamOut)
 {
   MOZ_ASSERT(aBaseDir);
   MOZ_ASSERT(aStreamOut);
 
   nsCOMPtr<nsIFile> finalFile;
   nsresult rv = BodyIdToFile(aBaseDir, aId, BODY_FILE_FINAL,
                              getter_AddRefs(finalFile));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -229,17 +241,17 @@ FileUtils::BodyOpen(const QuotaInfo& aQu
 
   fileStream.forget(aStreamOut);
 
   return rv;
 }
 
 // static
 nsresult
-FileUtils::BodyDeleteFiles(nsIFile* aBaseDir, const nsTArray<nsID>& aIdList)
+BodyDeleteFiles(nsIFile* aBaseDir, const nsTArray<nsID>& aIdList)
 {
   nsresult rv = NS_OK;
 
   for (uint32_t i = 0; i < aIdList.Length(); ++i) {
     nsCOMPtr<nsIFile> tmpFile;
     rv = BodyIdToFile(aBaseDir, aIdList[i], BODY_FILE_TMP,
                       getter_AddRefs(tmpFile));
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -268,20 +280,21 @@ FileUtils::BodyDeleteFiles(nsIFile* aBas
 
     // Again, only treat removal as hard failure in debug build.
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   return NS_OK;
 }
 
-// static
+namespace {
+
 nsresult
-FileUtils::BodyIdToFile(nsIFile* aBaseDir, const nsID& aId,
-                        BodyFileType aType, nsIFile** aBodyFileOut)
+BodyIdToFile(nsIFile* aBaseDir, const nsID& aId, BodyFileType aType,
+             nsIFile** aBodyFileOut)
 {
   MOZ_ASSERT(aBaseDir);
   MOZ_ASSERT(aBodyFileOut);
 
   *aBodyFileOut = nullptr;
 
   nsresult rv = BodyGetCacheDir(aBaseDir, aId, aBodyFileOut);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -299,11 +312,13 @@ FileUtils::BodyIdToFile(nsIFile* aBaseDi
   }
 
   rv = (*aBodyFileOut)->Append(fileName);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   return rv;
 }
 
+} // anonymous namespace
+
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
--- a/dom/cache/FileUtils.h
+++ b/dom/cache/FileUtils.h
@@ -14,59 +14,44 @@
 
 struct nsID;
 class nsIFile;
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
-// TODO: remove static class and use functions in cache namespace (bug 1110485)
-class FileUtils final
-{
-public:
-  enum BodyFileType
-  {
-    BODY_FILE_FINAL,
-    BODY_FILE_TMP
-  };
+nsresult
+BodyCreateDir(nsIFile* aBaseDir);
 
-  static nsresult BodyCreateDir(nsIFile* aBaseDir);
-  // Note that this function can only be used during the initialization of the
-  // database.  We're unlikely to be able to delete the DB successfully past
-  // that point due to the file being in use.
-  static nsresult BodyDeleteDir(nsIFile* aBaseDir);
-  static nsresult BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId,
-                                  nsIFile** aCacheDirOut);
+// Note that this function can only be used during the initialization of the
+// database.  We're unlikely to be able to delete the DB successfully past
+// that point due to the file being in use.
+nsresult
+BodyDeleteDir(nsIFile* aBaseDir);
+
+nsresult
+BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId, nsIFile** aCacheDirOut);
 
-  static nsresult
-  BodyStartWriteStream(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
-                       nsIInputStream* aSource, void* aClosure,
-                       nsAsyncCopyCallbackFun aCallback, nsID* aIdOut,
-                       nsISupports** aCopyContextOut);
+nsresult
+BodyStartWriteStream(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
+                     nsIInputStream* aSource, void* aClosure,
+                     nsAsyncCopyCallbackFun aCallback, nsID* aIdOut,
+                     nsISupports** aCopyContextOut);
 
-  static void
-  BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext);
-
-  static nsresult
-  BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId);
+void
+BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext);
 
-  static nsresult
-  BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, const nsID& aId,
-           nsIInputStream** aStreamOut);
-
-  static nsresult
-  BodyDeleteFiles(nsIFile* aBaseDir, const nsTArray<nsID>& aIdList);
+nsresult
+BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId);
 
-private:
-  static nsresult
-  BodyIdToFile(nsIFile* aBaseDir, const nsID& aId, BodyFileType aType,
-               nsIFile** aBodyFileOut);
+nsresult
+BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, const nsID& aId,
+         nsIInputStream** aStreamOut);
 
-  FileUtils() = delete;
-  ~FileUtils() = delete;
-};
+nsresult
+BodyDeleteFiles(nsIFile* aBaseDir, const nsTArray<nsID>& aIdList);
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_cache_FileUtils_h
--- a/dom/cache/IPCUtils.h
+++ b/dom/cache/IPCUtils.h
@@ -3,20 +3,57 @@
 /* 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/. */
 
 #ifndef mozilla_dom_cache_IPCUtils_h
 #define mozilla_dom_cache_IPCUtils_h
 
 #include "ipc/IPCMessageUtils.h"
+
+// Fix X11 header brain damage that conflicts with HeadersGuardEnum::None
+#undef None
+
+#include "mozilla/dom/HeadersBinding.h"
+#include "mozilla/dom/RequestBinding.h"
+#include "mozilla/dom/ResponseBinding.h"
 #include "mozilla/dom/cache/Types.h"
 
 namespace IPC {
   template<>
+  struct ParamTraits<mozilla::dom::HeadersGuardEnum> :
+    public ContiguousEnumSerializer<mozilla::dom::HeadersGuardEnum,
+                                    mozilla::dom::HeadersGuardEnum::None,
+                                    mozilla::dom::HeadersGuardEnum::EndGuard_> {};
+  template<>
+  struct ParamTraits<mozilla::dom::RequestMode> :
+    public ContiguousEnumSerializer<mozilla::dom::RequestMode,
+                                    mozilla::dom::RequestMode::Same_origin,
+                                    mozilla::dom::RequestMode::EndGuard_> {};
+  template<>
+  struct ParamTraits<mozilla::dom::RequestCredentials> :
+    public ContiguousEnumSerializer<mozilla::dom::RequestCredentials,
+                                    mozilla::dom::RequestCredentials::Omit,
+                                    mozilla::dom::RequestCredentials::EndGuard_> {};
+  template<>
+  struct ParamTraits<mozilla::dom::RequestCache> :
+    public ContiguousEnumSerializer<mozilla::dom::RequestCache,
+                                    mozilla::dom::RequestCache::Default,
+                                    mozilla::dom::RequestCache::EndGuard_> {};
+  template<>
+  struct ParamTraits<mozilla::dom::RequestContext> :
+    public ContiguousEnumSerializer<mozilla::dom::RequestContext,
+                                    mozilla::dom::RequestContext::Audio,
+                                    mozilla::dom::RequestContext::EndGuard_> {};
+  template<>
+  struct ParamTraits<mozilla::dom::ResponseType> :
+    public ContiguousEnumSerializer<mozilla::dom::ResponseType,
+                                    mozilla::dom::ResponseType::Basic,
+                                    mozilla::dom::ResponseType::EndGuard_> {};
+  template<>
   struct ParamTraits<mozilla::dom::cache::Namespace> :
     public ContiguousEnumSerializer<mozilla::dom::cache::Namespace,
                                     mozilla::dom::cache::DEFAULT_NAMESPACE,
                                     mozilla::dom::cache::NUMBER_OF_NAMESPACES>
   {};
 }
 
 #endif // mozilla_dom_cache_IPCUtils_h
--- a/dom/cache/Manager.cpp
+++ b/dom/cache/Manager.cpp
@@ -11,17 +11,17 @@
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/cache/Context.h"
 #include "mozilla/dom/cache/DBAction.h"
 #include "mozilla/dom/cache/DBSchema.h"
 #include "mozilla/dom/cache/FileUtils.h"
 #include "mozilla/dom/cache/ManagerId.h"
-#include "mozilla/dom/cache/PCacheTypes.h"
+#include "mozilla/dom/cache/CacheTypes.h"
 #include "mozilla/dom/cache/SavedTypes.h"
 #include "mozilla/dom/cache/StreamList.h"
 #include "mozilla/dom/cache/Types.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozStorageHelper.h"
 #include "nsAutoPtr.h"
 #include "nsIInputStream.h"
 #include "nsID.h"
@@ -29,20 +29,21 @@
 #include "nsIThread.h"
 #include "nsThreadUtils.h"
 #include "nsTObserverArray.h"
 
 namespace {
 
 using mozilla::unused;
 using mozilla::dom::cache::Action;
-using mozilla::dom::cache::DBSchema;
-using mozilla::dom::cache::FileUtils;
+using mozilla::dom::cache::BodyCreateDir;
+using mozilla::dom::cache::BodyDeleteFiles;
 using mozilla::dom::cache::QuotaInfo;
 using mozilla::dom::cache::SyncDBAction;
+using mozilla::dom::cache::db::CreateSchema;
 
 // An Action that is executed when a Context is first created.  It ensures that
 // the directory and database are setup properly.  This lets other actions
 // not worry about these details.
 class SetupAction final : public SyncDBAction
 {
 public:
   SetupAction()
@@ -54,23 +55,23 @@ public:
                         mozIStorageConnection* aConn) override
   {
     // TODO: init maintainance marker (bug 1110446)
     // TODO: perform maintainance if necessary (bug 1110446)
     // TODO: find orphaned caches in database (bug 1110446)
     // TODO: have Context create/delete marker files in constructor/destructor
     //       and only do expensive maintenance if that marker is present (bug 1110446)
 
-    nsresult rv = FileUtils::BodyCreateDir(aDBDir);
+    nsresult rv = BodyCreateDir(aDBDir);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     mozStorageTransaction trans(aConn, false,
                                 mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
-    rv = DBSchema::CreateSchema(aConn);
+    rv = CreateSchema(aConn);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = trans.Commit();
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     return rv;
   }
 };
@@ -108,17 +109,17 @@ public:
     }
 
     rv = dbDir->Append(NS_LITERAL_STRING("cache"));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       aResolver->Resolve(rv);
       return;
     }
 
-    rv = FileUtils::BodyDeleteFiles(dbDir, mDeletedBodyIdList);
+    rv = BodyDeleteFiles(dbDir, mDeletedBodyIdList);
     unused << NS_WARN_IF(NS_FAILED(rv));
 
     aResolver->Resolve(rv);
   }
 
 private:
   nsTArray<nsID> mDeletedBodyIdList;
 };
@@ -151,16 +152,17 @@ public:
     nsRefPtr<Manager> ref = Get(aManagerId);
     if (!ref) {
       // TODO: replace this with a thread pool (bug 1119864)
       nsCOMPtr<nsIThread> ioThread;
       rv = NS_NewNamedThread("DOMCacheThread", getter_AddRefs(ioThread));
       if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
       ref = new Manager(aManagerId, ioThread);
+      ref->Init();
 
       MOZ_ASSERT(!sFactory->mManagerList.Contains(ref));
       sFactory->mManagerList.AppendElement(ref);
     }
 
     ref.forget(aManagerOut);
 
     return NS_OK;
@@ -175,17 +177,17 @@ public:
     if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; }
 
     ManagerList::ForwardIterator iter(sFactory->mManagerList);
     while (iter.HasMore()) {
       nsRefPtr<Manager> manager = iter.GetNext();
       // If there is an invalid Manager finishing up and a new Manager
       // is created for the same origin, then the new Manager will
       // be blocked until QuotaManager finishes clearing the origin.
-      if (manager->IsValid() && *manager->mManagerId == *aManagerId) {
+      if (!manager->IsClosing() && *manager->mManagerId == *aManagerId) {
         return manager.forget();
       }
     }
 
     return nullptr;
   }
 
   static void
@@ -404,43 +406,41 @@ StaticRefPtr<nsIThread> Manager::Factory
 // ----------------------------------------------------------------------------
 
 // Abstract class to help implement the various Actions.  The vast majority
 // of Actions are synchronous and need to report back to a Listener on the
 // Manager.
 class Manager::BaseAction : public SyncDBAction
 {
 protected:
-  BaseAction(Manager* aManager, ListenerId aListenerId, RequestId aRequestId)
+  BaseAction(Manager* aManager, ListenerId aListenerId)
     : SyncDBAction(DBAction::Existing)
     , mManager(aManager)
     , mListenerId(aListenerId)
-    , mRequestId (aRequestId)
   {
   }
 
   virtual void
-  Complete(Listener* aListener, nsresult aRv) = 0;
+  Complete(Listener* aListener, ErrorResult&& aRv) = 0;
 
   virtual void
   CompleteOnInitiatingThread(nsresult aRv) override
   {
     NS_ASSERT_OWNINGTHREAD(Manager::BaseAction);
     Listener* listener = mManager->GetListener(mListenerId);
     if (listener) {
-      Complete(listener, aRv);
+      Complete(listener, ErrorResult(aRv));
     }
 
     // ensure we release the manager on the initiating thread
     mManager = nullptr;
   }
 
   nsRefPtr<Manager> mManager;
   const ListenerId mListenerId;
-  const RequestId mRequestId;
 };
 
 // ----------------------------------------------------------------------------
 
 // Action that is executed when we determine that content has stopped using
 // a Cache object that has been orphaned.
 class Manager::DeleteOrphanedCacheAction final : public SyncDBAction
 {
@@ -453,17 +453,17 @@ public:
 
   virtual nsresult
   RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
                         mozIStorageConnection* aConn) override
   {
     mozStorageTransaction trans(aConn, false,
                                 mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
-    nsresult rv = DBSchema::DeleteCache(aConn, mCacheId, mDeletedBodyIdList);
+    nsresult rv = db::DeleteCacheId(aConn, mCacheId, mDeletedBodyIdList);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = trans.Commit();
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     return rv;
   }
 
@@ -483,158 +483,149 @@ private:
 };
 
 // ----------------------------------------------------------------------------
 
 class Manager::CacheMatchAction final : public Manager::BaseAction
 {
 public:
   CacheMatchAction(Manager* aManager, ListenerId aListenerId,
-                   RequestId aRequestId, CacheId aCacheId,
-                   const PCacheRequest& aRequest,
-                   const PCacheQueryParams& aParams,
+                   CacheId aCacheId, const CacheMatchArgs& aArgs,
                    StreamList* aStreamList)
-    : BaseAction(aManager, aListenerId, aRequestId)
+    : BaseAction(aManager, aListenerId)
     , mCacheId(aCacheId)
-    , mRequest(aRequest)
-    , mParams(aParams)
+    , mArgs(aArgs)
     , mStreamList(aStreamList)
     , mFoundResponse(false)
   { }
 
   virtual nsresult
   RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
                         mozIStorageConnection* aConn) override
   {
-    nsresult rv = DBSchema::CacheMatch(aConn, mCacheId, mRequest, mParams,
-                                       &mFoundResponse, &mResponse);
+    nsresult rv = db::CacheMatch(aConn, mCacheId, mArgs.request(),
+                                 mArgs.params(), &mFoundResponse, &mResponse);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     if (!mFoundResponse || !mResponse.mHasBodyId) {
       return rv;
     }
 
     nsCOMPtr<nsIInputStream> stream;
-    rv = FileUtils::BodyOpen(aQuotaInfo, aDBDir, mResponse.mBodyId,
-                             getter_AddRefs(stream));
+    rv = BodyOpen(aQuotaInfo, aDBDir, mResponse.mBodyId, getter_AddRefs(stream));
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     if (NS_WARN_IF(!stream)) { return NS_ERROR_FILE_NOT_FOUND; }
 
     mStreamList->Add(mResponse.mBodyId, stream);
 
     return rv;
   }
 
   virtual void
-  Complete(Listener* aListener, nsresult aRv) override
+  Complete(Listener* aListener, ErrorResult&& aRv) override
   {
     if (!mFoundResponse) {
-      aListener->OnCacheMatch(mRequestId, aRv, nullptr, nullptr);
+      aListener->OnOpComplete(Move(aRv), CacheMatchResult(void_t()));
     } else {
       mStreamList->Activate(mCacheId);
-      aListener->OnCacheMatch(mRequestId, aRv, &mResponse, mStreamList);
+      aListener->OnOpComplete(Move(aRv), CacheMatchResult(void_t()), mResponse,
+                              mStreamList);
     }
     mStreamList = nullptr;
   }
 
   virtual bool MatchesCacheId(CacheId aCacheId) const override
   {
     return aCacheId == mCacheId;
   }
 
 private:
   const CacheId mCacheId;
-  const PCacheRequest mRequest;
-  const PCacheQueryParams mParams;
+  const CacheMatchArgs mArgs;
   nsRefPtr<StreamList> mStreamList;
   bool mFoundResponse;
   SavedResponse mResponse;
 };
 
 // ----------------------------------------------------------------------------
 
 class Manager::CacheMatchAllAction final : public Manager::BaseAction
 {
 public:
   CacheMatchAllAction(Manager* aManager, ListenerId aListenerId,
-                      RequestId aRequestId, CacheId aCacheId,
-                      const PCacheRequestOrVoid& aRequestOrVoid,
-                      const PCacheQueryParams& aParams,
+                      CacheId aCacheId, const CacheMatchAllArgs& aArgs,
                       StreamList* aStreamList)
-    : BaseAction(aManager, aListenerId, aRequestId)
+    : BaseAction(aManager, aListenerId)
     , mCacheId(aCacheId)
-    , mRequestOrVoid(aRequestOrVoid)
-    , mParams(aParams)
+    , mArgs(aArgs)
     , mStreamList(aStreamList)
   { }
 
   virtual nsresult
   RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
                         mozIStorageConnection* aConn) override
   {
-    nsresult rv = DBSchema::CacheMatchAll(aConn, mCacheId, mRequestOrVoid,
-                                          mParams, mSavedResponses);
+    nsresult rv = db::CacheMatchAll(aConn, mCacheId, mArgs.requestOrVoid(),
+                                    mArgs.params(), mSavedResponses);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     for (uint32_t i = 0; i < mSavedResponses.Length(); ++i) {
       if (!mSavedResponses[i].mHasBodyId) {
         continue;
       }
 
       nsCOMPtr<nsIInputStream> stream;
-      rv = FileUtils::BodyOpen(aQuotaInfo, aDBDir,
-                               mSavedResponses[i].mBodyId,
-                               getter_AddRefs(stream));
+      rv = BodyOpen(aQuotaInfo, aDBDir, mSavedResponses[i].mBodyId,
+                    getter_AddRefs(stream));
       if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
       if (NS_WARN_IF(!stream)) { return NS_ERROR_FILE_NOT_FOUND; }
 
       mStreamList->Add(mSavedResponses[i].mBodyId, stream);
     }
 
     return rv;
   }
 
   virtual void
-  Complete(Listener* aListener, nsresult aRv) override
+  Complete(Listener* aListener, ErrorResult&& aRv) override
   {
     mStreamList->Activate(mCacheId);
-    aListener->OnCacheMatchAll(mRequestId, aRv, mSavedResponses, mStreamList);
+    aListener->OnOpComplete(Move(aRv), CacheMatchAllResult(), mSavedResponses,
+                            mStreamList);
     mStreamList = nullptr;
   }
 
   virtual bool MatchesCacheId(CacheId aCacheId) const override
   {
     return aCacheId == mCacheId;
   }
 
 private:
   const CacheId mCacheId;
-  const PCacheRequestOrVoid mRequestOrVoid;
-  const PCacheQueryParams mParams;
+  const CacheMatchAllArgs mArgs;
   nsRefPtr<StreamList> mStreamList;
   nsTArray<SavedResponse> mSavedResponses;
 };
 
 // ----------------------------------------------------------------------------
 
 // This is the most complex Action.  It puts a request/response pair into the
 // Cache.  It does not complete until all of the body data has been saved to
 // disk.  This means its an asynchronous Action.
 class Manager::CachePutAllAction final : public DBAction
 {
 public:
   CachePutAllAction(Manager* aManager, ListenerId aListenerId,
-                    RequestId aRequestId, CacheId aCacheId,
+                    CacheId aCacheId,
                     const nsTArray<CacheRequestResponse>& aPutList,
                     const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
                     const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList)
     : DBAction(DBAction::Existing)
     , mManager(aManager)
     , mListenerId(aListenerId)
-    , mRequestId(aRequestId)
     , mCacheId(aCacheId)
     , mList(aPutList.Length())
     , mExpectedAsyncCopyCompletions(1)
     , mAsyncResult(NS_OK)
     , mMutex("cache::Manager::CachePutAllAction")
   {
     MOZ_ASSERT(!aPutList.IsEmpty());
     MOZ_ASSERT(aPutList.Length() == aRequestStreamList.Length());
@@ -763,35 +754,35 @@ private:
 
     mozStorageTransaction trans(mConn, false,
                                 mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
     nsresult rv = NS_OK;
     for (uint32_t i = 0; i < mList.Length(); ++i) {
       Entry& e = mList[i];
       if (e.mRequestStream) {
-        rv = FileUtils::BodyFinalizeWrite(mDBDir, e.mRequestBodyId);
+        rv = BodyFinalizeWrite(mDBDir, e.mRequestBodyId);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           DoResolve(rv);
           return;
         }
       }
       if (e.mResponseStream) {
-        rv = FileUtils::BodyFinalizeWrite(mDBDir, e.mResponseBodyId);
+        rv = BodyFinalizeWrite(mDBDir, e.mResponseBodyId);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           DoResolve(rv);
           return;
         }
       }
 
-      rv = DBSchema::CachePut(mConn, mCacheId, e.mRequest,
-                              e.mRequestStream ? &e.mRequestBodyId : nullptr,
-                              e.mResponse,
-                              e.mResponseStream ? &e.mResponseBodyId : nullptr,
-                              mDeletedBodyIdList);
+      rv = db::CachePut(mConn, mCacheId, e.mRequest,
+                        e.mRequestStream ? &e.mRequestBodyId : nullptr,
+                        e.mResponse,
+                        e.mResponseStream ? &e.mResponseBodyId : nullptr,
+                        mDeletedBodyIdList);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         DoResolve(rv);
         return;
       }
     }
 
     rv = trans.Commit();
     unused << NS_WARN_IF(NS_FAILED(rv));
@@ -809,17 +800,17 @@ private:
       mList[i].mResponseStream = nullptr;
     }
 
     mManager->NoteOrphanedBodyIdList(mDeletedBodyIdList);
 
     Listener* listener = mManager->GetListener(mListenerId);
     mManager = nullptr;
     if (listener) {
-      listener->OnCachePutAll(mRequestId, aRv);
+      listener->OnOpComplete(ErrorResult(aRv), CachePutAllResult());
     }
   }
 
   virtual void
   CancelOnInitiatingThread() override
   {
     NS_ASSERT_OWNINGTHREAD(Action);
     Action::CancelOnInitiatingThread();
@@ -829,22 +820,22 @@ private:
   virtual bool MatchesCacheId(CacheId aCacheId) const override
   {
     NS_ASSERT_OWNINGTHREAD(Action);
     return aCacheId == mCacheId;
   }
 
   struct Entry
   {
-    PCacheRequest mRequest;
+    CacheRequest mRequest;
     nsCOMPtr<nsIInputStream> mRequestStream;
     nsID mRequestBodyId;
     nsCOMPtr<nsISupports> mRequestCopyContext;
 
-    PCacheResponse mResponse;
+    CacheResponse mResponse;
     nsCOMPtr<nsIInputStream> mResponseStream;
     nsID mResponseBodyId;
     nsCOMPtr<nsISupports> mResponseCopyContext;
   };
 
   enum StreamId
   {
     RequestStream,
@@ -875,20 +866,19 @@ private:
     }
 
     if (!source) {
       return NS_OK;
     }
 
     nsCOMPtr<nsISupports> copyContext;
 
-    nsresult rv = FileUtils::BodyStartWriteStream(aQuotaInfo, mDBDir, source,
-                                                  this, AsyncCopyCompleteFunc,
-                                                  bodyId,
-                                                  getter_AddRefs(copyContext));
+    nsresult rv = BodyStartWriteStream(aQuotaInfo, mDBDir, source, this,
+                                       AsyncCopyCompleteFunc, bodyId,
+                                       getter_AddRefs(copyContext));
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     mBodyIdWrittenList.AppendElement(*bodyId);
 
     if (copyContext) {
       MutexAutoLock lock(mMutex);
       mCopyContextList.AppendElement(copyContext);
     }
@@ -899,17 +889,17 @@ private:
   }
 
   void
   CancelAllStreamCopying()
   {
     // May occur on either owning thread or target thread
     MutexAutoLock lock(mMutex);
     for (uint32_t i = 0; i < mCopyContextList.Length(); ++i) {
-      FileUtils::BodyCancelWrite(mDBDir, mCopyContextList[i]);
+      BodyCancelWrite(mDBDir, mCopyContextList[i]);
     }
     mCopyContextList.Clear();
   }
 
   static void
   AsyncCopyCompleteFunc(void* aClosure, nsresult aRv)
   {
     // May be on any thread, including STS event target.
@@ -942,17 +932,17 @@ private:
     {
       MutexAutoLock lock(mMutex);
       MOZ_ASSERT(mCopyContextList.IsEmpty());
     }
 #endif
 
     // Clean up any files we might have written before hitting the error.
     if (NS_FAILED(aRv)) {
-      FileUtils::BodyDeleteFiles(mDBDir, mBodyIdWrittenList);
+      BodyDeleteFiles(mDBDir, mBodyIdWrittenList);
     }
 
     // Must be released on the target thread where it was opened.
     mConn = nullptr;
 
     // Drop our ref to the target thread as we are done with this thread.
     // Also makes our thread assertions catch any incorrect method calls
     // after resolve.
@@ -962,17 +952,16 @@ private:
     nsRefPtr<Action::Resolver> resolver;
     mResolver.swap(resolver);
     resolver->Resolve(aRv);
   }
 
   // initiating thread only
   nsRefPtr<Manager> mManager;
   const ListenerId mListenerId;
-  const RequestId mRequestId;
 
   // Set on initiating thread, read on target thread.  State machine guarantees
   // these are not modified while being read by the target thread.
   const CacheId mCacheId;
   nsTArray<Entry> mList;
   uint32_t mExpectedAsyncCopyCompletions;
 
   // target thread only
@@ -993,388 +982,425 @@ private:
 };
 
 // ----------------------------------------------------------------------------
 
 class Manager::CacheDeleteAction final : public Manager::BaseAction
 {
 public:
   CacheDeleteAction(Manager* aManager, ListenerId aListenerId,
-                    RequestId aRequestId, CacheId aCacheId,
-                    const PCacheRequest& aRequest,
-                    const PCacheQueryParams& aParams)
-    : BaseAction(aManager, aListenerId, aRequestId)
+                    CacheId aCacheId, const CacheDeleteArgs& aArgs)
+    : BaseAction(aManager, aListenerId)
     , mCacheId(aCacheId)
-    , mRequest(aRequest)
-    , mParams(aParams)
+    , mArgs(aArgs)
     , mSuccess(false)
   { }
 
   virtual nsresult
   RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
                         mozIStorageConnection* aConn) override
   {
     mozStorageTransaction trans(aConn, false,
                                 mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
-    nsresult rv = DBSchema::CacheDelete(aConn, mCacheId, mRequest, mParams,
-                                        mDeletedBodyIdList, &mSuccess);
+    nsresult rv = db::CacheDelete(aConn, mCacheId, mArgs.request(),
+                                  mArgs.params(), mDeletedBodyIdList,
+                                  &mSuccess);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     rv = trans.Commit();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       mSuccess = false;
       return rv;
     }
 
     return rv;
   }
 
   virtual void
-  Complete(Listener* aListener, nsresult aRv) override
+  Complete(Listener* aListener, ErrorResult&& aRv) override
   {
     mManager->NoteOrphanedBodyIdList(mDeletedBodyIdList);
-    aListener->OnCacheDelete(mRequestId, aRv, mSuccess);
+    aListener->OnOpComplete(Move(aRv), CacheDeleteResult(mSuccess));
   }
 
   virtual bool MatchesCacheId(CacheId aCacheId) const override
   {
     return aCacheId == mCacheId;
   }
 
 private:
   const CacheId mCacheId;
-  const PCacheRequest mRequest;
-  const PCacheQueryParams mParams;
+  const CacheDeleteArgs mArgs;
   bool mSuccess;
   nsTArray<nsID> mDeletedBodyIdList;
 };
 
 // ----------------------------------------------------------------------------
 
 class Manager::CacheKeysAction final : public Manager::BaseAction
 {
 public:
   CacheKeysAction(Manager* aManager, ListenerId aListenerId,
-                  RequestId aRequestId, CacheId aCacheId,
-                  const PCacheRequestOrVoid& aRequestOrVoid,
-                  const PCacheQueryParams& aParams,
+                  CacheId aCacheId, const CacheKeysArgs& aArgs,
                   StreamList* aStreamList)
-    : BaseAction(aManager, aListenerId, aRequestId)
+    : BaseAction(aManager, aListenerId)
     , mCacheId(aCacheId)
-    , mRequestOrVoid(aRequestOrVoid)
-    , mParams(aParams)
+    , mArgs(aArgs)
     , mStreamList(aStreamList)
   { }
 
   virtual nsresult
   RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
                         mozIStorageConnection* aConn) override
   {
-    nsresult rv = DBSchema::CacheKeys(aConn, mCacheId, mRequestOrVoid, mParams,
-                                      mSavedRequests);
+    nsresult rv = db::CacheKeys(aConn, mCacheId, mArgs.requestOrVoid(),
+                                mArgs.params(), mSavedRequests);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     for (uint32_t i = 0; i < mSavedRequests.Length(); ++i) {
       if (!mSavedRequests[i].mHasBodyId) {
         continue;
       }
 
       nsCOMPtr<nsIInputStream> stream;
-      rv = FileUtils::BodyOpen(aQuotaInfo, aDBDir,
-                               mSavedRequests[i].mBodyId,
-                               getter_AddRefs(stream));
+      rv = BodyOpen(aQuotaInfo, aDBDir, mSavedRequests[i].mBodyId,
+                    getter_AddRefs(stream));
       if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
       if (NS_WARN_IF(!stream)) { return NS_ERROR_FILE_NOT_FOUND; }
 
       mStreamList->Add(mSavedRequests[i].mBodyId, stream);
     }
 
     return rv;
   }
 
   virtual void
-  Complete(Listener* aListener, nsresult aRv) override
+  Complete(Listener* aListener, ErrorResult&& aRv) override
   {
     mStreamList->Activate(mCacheId);