Merge inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 13 Jan 2017 15:43:52 -0800
changeset 374362 87a39313365a178ce080e5613ee7b29b107e684e
parent 374297 671a2f8542cadcf9aad318ab76250a730a03b240 (current diff)
parent 374361 4ef05cc6af4ec1ff02dc6ceb0e85c1ee3a3f9e86 (diff)
child 374363 ee205312f370c1b6fbbaa20f6bb9eac4aa95d06f
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.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 MozReview-Commit-ID: JcbGWqzzYJj
layout/style/CSSStyleSheet.cpp
media/gmp-clearkey/0.1/AnnexB.cpp
media/gmp-clearkey/0.1/AnnexB.h
media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.cpp
media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.h
media/gmp-clearkey/0.1/clearkey.info.in
media/gmp-clearkey/0.1/gmp-task-utils-generated.h
media/gmp-clearkey/0.1/gmp-task-utils.h
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -797,16 +797,16 @@ bin/libfreebl_32int64_3.so
 #endif
 
 #ifdef PACKAGE_MOZTT
 @RESPATH@/fonts/*
 #endif
 
 ; media
 @RESPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
-@RESPATH@/gmp-clearkey/0.1/clearkey.info
+@RESPATH@/gmp-clearkey/0.1/manifest.json
 
 #ifdef PKG_LOCALE_MANIFEST
 #include @PKG_LOCALE_MANIFEST@
 #endif
 
 @RESPATH@/components/simpleServices.js
 @RESPATH@/components/utils.manifest
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1420,20 +1420,26 @@ pref("privacy.trackingprotection.ui.enab
 pref("privacy.trackingprotection.introCount", 0);
 pref("privacy.trackingprotection.introURL", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tracking-protection/start/");
 
 // Enable Contextual Identity Containers
 #ifdef NIGHTLY_BUILD
 pref("privacy.userContext.enabled", true);
 pref("privacy.userContext.ui.enabled", true);
 pref("privacy.usercontext.about_newtab_segregation.enabled", true);
+
+// 0 disables long press, 1 when clicked, the menu is shown, 2 the menu is shown after X milliseconds.
+pref("privacy.userContext.longPressBehavior", 2);
 #else
 pref("privacy.userContext.enabled", false);
 pref("privacy.userContext.ui.enabled", false);
 pref("privacy.usercontext.about_newtab_segregation.enabled", false);
+
+// 0 disables long press, 1 when clicked, the menu is shown, 2 the menu is shown after X milliseconds.
+pref("privacy.userContext.longPressBehavior", 0);
 #endif
 
 #ifndef RELEASE_OR_BETA
 // At the moment, autostart.2 is used, while autostart.1 is unused.
 // We leave it here set to false to reset users' defaults and allow
 // us to change everybody to true in the future, when desired.
 pref("browser.tabs.remote.autostart.1", false);
 pref("browser.tabs.remote.autostart.2", true);
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -5471,24 +5471,24 @@
           window.addEventListener("load", this, false);
 
           try {
             this._tabAnimationLoggingEnabled = Services.prefs.getBoolPref("browser.tabs.animationLogging.enabled");
           } catch (ex) {
             this._tabAnimationLoggingEnabled = false;
           }
           this._browserNewtabpageEnabled = Services.prefs.getBoolPref("browser.newtabpage.enabled");
+          Services.prefs.addObserver("privacy.userContext", this, false);
           this.observe(null, "nsPref:changed", "privacy.userContext.enabled");
-          Services.prefs.addObserver("privacy.userContext.enabled", this, false);
         ]]>
       </constructor>
 
       <destructor>
         <![CDATA[
-          Services.prefs.removeObserver("privacy.userContext.enabled", this);
+          Services.prefs.removeObserver("privacy.userContext", this);
         ]]>
       </destructor>
 
       <field name="tabbrowser" readonly="true">
         document.getElementById(this.getAttribute("tabbrowser"));
       </field>
 
       <field name="tabbox" readonly="true">
@@ -5514,52 +5514,65 @@
 
       <method name="observe">
         <parameter name="aSubject"/>
         <parameter name="aTopic"/>
         <parameter name="aData"/>
         <body><![CDATA[
           switch (aTopic) {
             case "nsPref:changed":
-              // This is the only pref observed.
+              // This is has to deal with changes in
+              // privacy.userContext.enabled and
+              // privacy.userContext.longPressBehavior.
               let containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled")
                                         && !PrivateBrowsingUtils.isWindowPrivate(window);
 
+              // This pref won't change so often, so just recreate the menu.
+              let longPressBehavior = Services.prefs.getIntPref("privacy.userContext.longPressBehavior");
+
+              // If longPressBehavior pref is set to 0 (or any invalid value)
+              // long press menu is disabled.
+              if (containersEnabled && (longPressBehavior <= 0 || longPressBehavior > 2)) {
+                containersEnabled = false;
+              }
+
               const newTab = document.getElementById("new-tab-button");
               const newTab2 = document.getAnonymousElementByAttribute(this, "anonid", "tabs-newtab-button")
 
-              if (containersEnabled) {
-                for (let parent of [newTab, newTab2]) {
-                  if (!parent)
-                    continue;
+              for (let parent of [newTab, newTab2]) {
+                if (!parent)
+                  continue;
+
+                gClickAndHoldListenersOnElement.remove(parent);
+                parent.removeAttribute("type");
+                if (parent.firstChild) {
+                  parent.firstChild.remove();
+                }
+
+                if (containersEnabled) {
                   let popup = document.createElementNS(
                                 "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
                                 "menupopup");
                   if (parent.id) {
                     popup.id = "newtab-popup";
                   } else {
                     popup.setAttribute("anonid", "newtab-popup");
                   }
                   popup.className = "new-tab-popup";
                   popup.setAttribute("position", "after_end");
                   parent.appendChild(popup);
 
-                  gClickAndHoldListenersOnElement.add(parent);
+                  // longPressBehavior == 2 means that the menu is shown after X
+                  // millisecs. Otherwise, with 1, the menu is open immediatelly.
+                  if (longPressBehavior == 2) {
+                    gClickAndHoldListenersOnElement.add(parent);
+                  }
+
                   parent.setAttribute("type", "menu");
                 }
-              } else {
-                for (let parent of [newTab, newTab2]) {
-                  if (!parent)
-                    continue;
-                  gClickAndHoldListenersOnElement.remove(parent);
-                  parent.removeAttribute("type");
-                  if (!parent.firstChild)
-                    continue;
-                  parent.firstChild.remove();
-                }
               }
 
               break;
           }
         ]]></body>
       </method>
 
       <property name="_isCustomizing" readonly="true">
--- a/browser/components/contextualidentity/test/browser/browser_newtabButton.js
+++ b/browser/components/contextualidentity/test/browser/browser_newtabButton.js
@@ -1,16 +1,17 @@
 "use strict";
 
 // Testing that when the user opens the add tab menu and clicks menu items
 // the correct context id is opened
 
-add_task(function* test() {
+add_task(function* test_menu_with_timeout() {
   yield SpecialPowers.pushPrefEnv({"set": [
-      ["privacy.userContext.enabled", true]
+      ["privacy.userContext.enabled", true],
+      ["privacy.userContext.longPressBehavior", 2]
   ]});
 
   let newTab = document.getElementById('tabbrowser-tabs');
   let newTabButton = document.getAnonymousElementByAttribute(newTab, "anonid", "tabs-newtab-button");
   ok(newTabButton, "New tab button exists");
   ok(!newTabButton.hidden, "New tab button is visible");
   yield BrowserTestUtils.waitForCondition(() => !!document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup"), "Wait for popup to exist");
   let popup = document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup");
@@ -29,16 +30,61 @@ add_task(function* test() {
 
     let tab = yield waitForTabPromise;
 
     is(tab.getAttribute('usercontextid'), i, `New tab has UCI equal ${i}`);
     yield BrowserTestUtils.removeTab(tab);
   }
 });
 
+add_task(function* test_menu_without_timeout() {
+  yield SpecialPowers.pushPrefEnv({"set": [
+      ["privacy.userContext.enabled", true],
+      ["privacy.userContext.longPressBehavior", 1]
+  ]});
+
+  let newTab = document.getElementById('tabbrowser-tabs');
+  let newTabButton = document.getAnonymousElementByAttribute(newTab, "anonid", "tabs-newtab-button");
+  ok(newTabButton, "New tab button exists");
+  ok(!newTabButton.hidden, "New tab button is visible");
+  yield BrowserTestUtils.waitForCondition(() => !!document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup"), "Wait for popup to exist");
+  let popup = document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup");
+
+  for (let i = 1; i <= 4; i++) {
+    let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
+    EventUtils.synthesizeMouseAtCenter(newTabButton, {type: "mousedown"});
+
+    yield popupShownPromise;
+    let contextIdItem = popup.querySelector(`menuitem[data-usercontextid="${i}"]`);
+
+    ok(contextIdItem, `User context id ${i} exists`);
+
+    let waitForTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
+    EventUtils.synthesizeMouseAtCenter(contextIdItem, {});
+
+    let tab = yield waitForTabPromise;
+
+    is(tab.getAttribute('usercontextid'), i, `New tab has UCI equal ${i}`);
+    yield BrowserTestUtils.removeTab(tab);
+  }
+});
+
+add_task(function* test_no_menu() {
+  yield SpecialPowers.pushPrefEnv({"set": [
+      ["privacy.userContext.enabled", true],
+      ["privacy.userContext.longPressBehavior", 0]
+  ]});
+
+  let newTab = document.getElementById('tabbrowser-tabs');
+  let newTabButton = document.getAnonymousElementByAttribute(newTab, "anonid", "tabs-newtab-button");
+  ok(newTabButton, "New tab button exists");
+  ok(!newTabButton.hidden, "New tab button is visible");
+  let popup = document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup");
+  ok(!popup, "new tab should not have a popup");
+});
 
 add_task(function* test_private_mode() {
   let privateWindow = yield BrowserTestUtils.openNewBrowserWindow({private: true});
   let privateDocument = privateWindow.document;
   let {tabContainer} = privateWindow.gBrowser;
   let newTab = privateDocument.getAnonymousElementByAttribute(tabContainer, "anonid", "tabs-newtab-button");
   let newTab2 = privateDocument.getElementById("new-tab-button");
   // Check to ensure we are talking about the right button
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -792,17 +792,17 @@ bin/libfreebl_32int64_3.so
 
 #if defined(MOZ_ASAN) && defined(CLANG_CL)
 @BINPATH@/clang_rt.asan_dynamic-*.dll
 #endif
 
 
 ; media
 @RESPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
-@RESPATH@/gmp-clearkey/0.1/clearkey.info
+@RESPATH@/gmp-clearkey/0.1/manifest.json
 
 ; gfx
 #ifdef XP_WIN
 @RESPATH@/components/GfxSanityTest.manifest
 @RESPATH@/components/SanityTest.js
 #endif
 
 #ifdef MOZ_MULET
--- a/browser/modules/test/browser_UsageTelemetry_content.js
+++ b/browser/modules/test/browser_UsageTelemetry_content.js
@@ -23,22 +23,26 @@ add_task(function* setup() {
   let engineOneOff = Services.search.getEngineByName("MozSearch2");
   Services.search.moveEngine(engineOneOff, 0);
 
   yield SpecialPowers.pushPrefEnv({"set": [
     ["dom.select_events.enabled", true], // We want select events to be fired.
     ["toolkit.telemetry.enabled", true]  // And Extended Telemetry to be enabled.
   ]});
 
+  // Enable event recording for the events tested here.
+  Services.telemetry.setEventRecordingEnabled("navigation", true);
+
   // Make sure to restore the engine once we're done.
   registerCleanupFunction(function* () {
     Services.search.currentEngine = originalEngine;
     Services.search.removeEngine(engineDefault);
     Services.search.removeEngine(engineOneOff);
     yield PlacesTestUtils.clearHistory();
+    Services.telemetry.setEventRecordingEnabled("navigation", false);
   });
 });
 
 add_task(function* test_context_menu() {
   // Let's reset the Telemetry data.
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
--- a/browser/modules/test/browser_UsageTelemetry_content_aboutHome.js
+++ b/browser/modules/test/browser_UsageTelemetry_content_aboutHome.js
@@ -25,22 +25,26 @@ add_task(function* setup() {
 
   // Move the second engine at the beginning of the one-off list.
   let engineOneOff = Services.search.getEngineByName("MozSearch2");
   Services.search.moveEngine(engineOneOff, 0);
 
   // Enable Extended Telemetry.
   yield SpecialPowers.pushPrefEnv({"set": [["toolkit.telemetry.enabled", true]]});
 
+  // Enable event recording for the events tested here.
+  Services.telemetry.setEventRecordingEnabled("navigation", true);
+
   // Make sure to restore the engine once we're done.
   registerCleanupFunction(function* () {
     Services.search.currentEngine = originalEngine;
     Services.search.removeEngine(engineDefault);
     Services.search.removeEngine(engineOneOff);
     yield PlacesTestUtils.clearHistory();
+    Services.telemetry.setEventRecordingEnabled("navigation", false);
   });
 });
 
 add_task(function* test_abouthome_simpleQuery() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
--- a/browser/modules/test/browser_UsageTelemetry_searchbar.js
+++ b/browser/modules/test/browser_UsageTelemetry_searchbar.js
@@ -65,21 +65,25 @@ add_task(function* setup() {
 
   // Move the second engine at the beginning of the one-off list.
   let engineOneOff = Services.search.getEngineByName("MozSearch2");
   Services.search.moveEngine(engineOneOff, 0);
 
   // Enable Extended Telemetry.
   yield SpecialPowers.pushPrefEnv({"set": [["toolkit.telemetry.enabled", true]]});
 
+  // Enable event recording for the events tested here.
+  Services.telemetry.setEventRecordingEnabled("navigation", true);
+
   // Make sure to restore the engine once we're done.
   registerCleanupFunction(function* () {
     Services.search.currentEngine = originalEngine;
     Services.search.removeEngine(engineDefault);
     Services.search.removeEngine(engineOneOff);
+    Services.telemetry.setEventRecordingEnabled("navigation", false);
   });
 });
 
 add_task(function* test_plainQuery() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
--- a/browser/modules/test/browser_UsageTelemetry_urlbar.js
+++ b/browser/modules/test/browser_UsageTelemetry_urlbar.js
@@ -76,24 +76,28 @@ add_task(function* setup() {
 
   // Enable Extended Telemetry.
   yield SpecialPowers.pushPrefEnv({"set": [["toolkit.telemetry.enabled", true]]});
 
   // Enable local telemetry recording for the duration of the tests.
   let oldCanRecord = Services.telemetry.canRecordExtended;
   Services.telemetry.canRecordExtended = true;
 
+  // Enable event recording for the events tested here.
+  Services.telemetry.setEventRecordingEnabled("navigation", true);
+
   // Make sure to restore the engine once we're done.
   registerCleanupFunction(function* () {
     Services.telemetry.canRecordExtended = oldCanRecord;
     Services.search.currentEngine = originalEngine;
     Services.search.removeEngine(engine);
     Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF, true);
     Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
     yield PlacesTestUtils.clearHistory();
+    Services.telemetry.setEventRecordingEnabled("navigation", false);
   });
 });
 
 add_task(function* test_simpleQuery() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
   Services.telemetry.clearEvents();
   let resultIndexHist = Services.telemetry.getHistogramById("FX_URLBAR_SELECTED_RESULT_INDEX");
--- a/devtools/client/aboutdebugging/moz.build
+++ b/devtools/client/aboutdebugging/moz.build
@@ -7,8 +7,11 @@
 DIRS += [
     'components',
     'modules',
 ]
 
 BROWSER_CHROME_MANIFESTS += [
     'test/browser.ini'
 ]
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: about:debugging')
--- a/devtools/client/animationinspector/moz.build
+++ b/devtools/client/animationinspector/moz.build
@@ -9,8 +9,11 @@ XPCSHELL_TESTS_MANIFESTS += ['test/unit/
 
 DIRS += [
     'components'
 ]
 
 DevToolsModules(
     'utils.js',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Animation Inspector')
--- a/devtools/client/canvasdebugger/moz.build
+++ b/devtools/client/canvasdebugger/moz.build
@@ -3,8 +3,11 @@
 # 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/.
 
 DevToolsModules(
     'panel.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Canvas Debugger')
--- a/devtools/client/debugger/moz.build
+++ b/devtools/client/debugger/moz.build
@@ -13,8 +13,11 @@ DevToolsModules(
     'panel.js'
 )
 
 BROWSER_CHROME_MANIFESTS += [
   'new/test/mochitest/browser.ini',
   'test/mochitest/browser.ini',
   'test/mochitest/browser2.ini'
 ]
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Debugger')
--- a/devtools/client/dom/moz.build
+++ b/devtools/client/dom/moz.build
@@ -7,8 +7,11 @@ BROWSER_CHROME_MANIFESTS += ['test/brows
 
 DIRS += [
     'content',
 ]
 
 DevToolsModules(
     'dom-panel.js',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: DOM')
--- a/devtools/client/framework/moz.build
+++ b/devtools/client/framework/moz.build
@@ -30,8 +30,11 @@ DevToolsModules(
     'target.js',
     'toolbox-highlighter-utils.js',
     'toolbox-host-manager.js',
     'toolbox-hosts.js',
     'toolbox-options.js',
     'toolbox.js',
     'ToolboxProcess.jsm',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Framework')
--- a/devtools/client/inspector/moz.build
+++ b/devtools/client/inspector/moz.build
@@ -16,8 +16,11 @@ DevToolsModules(
     'breadcrumbs.js',
     'inspector-commands.js',
     'inspector-search.js',
     'panel.js',
     'toolsidebar.js',
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Inspector')
--- a/devtools/client/jsonview/moz.build
+++ b/devtools/client/jsonview/moz.build
@@ -16,8 +16,11 @@ DevToolsModules(
     'converter-sniffer.js',
     'json-viewer.js',
     'main.js',
     'utils.js',
     'viewer-config.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: JSON Viewer')
--- a/devtools/client/moz.build
+++ b/devtools/client/moz.build
@@ -47,8 +47,11 @@ EXTRA_COMPONENTS += [
 ]
 
 JAR_MANIFESTS += ['jar.mn']
 
 DevToolsModules(
     'definitions.js',
     'menus.js',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools')
--- a/devtools/client/netmonitor/moz.build
+++ b/devtools/client/netmonitor/moz.build
@@ -31,8 +31,11 @@ DevToolsModules(
     'sort-predicates.js',
     'statistics-view.js',
     'store.js',
     'toolbar-view.js',
     'waterfall-background.js',
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Netmonitor')
--- a/devtools/client/performance/moz.build
+++ b/devtools/client/performance/moz.build
@@ -12,8 +12,11 @@ DIRS += [
 
 DevToolsModules(
     'events.js',
     'panel.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Performance Tools (Profiler/Timeline)')
--- a/devtools/client/responsive.html/moz.build
+++ b/devtools/client/responsive.html/moz.build
@@ -21,8 +21,11 @@ DevToolsModules(
     'reducers.js',
     'responsive-ua.css',
     'store.js',
     'types.js',
 )
 
 XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Responsive Design Mode')
--- a/devtools/client/responsivedesign/moz.build
+++ b/devtools/client/responsivedesign/moz.build
@@ -4,8 +4,11 @@
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 DevToolsModules(
     'resize-commands.js',
     'responsivedesign-child.js',
     'responsivedesign.jsm',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Responsive Design Mode')
--- a/devtools/client/scratchpad/moz.build
+++ b/devtools/client/scratchpad/moz.build
@@ -6,8 +6,11 @@
 
 DevToolsModules(
     'scratchpad-commands.js',
     'scratchpad-manager.jsm',
     'scratchpad-panel.js',
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Scratchpad')
--- a/devtools/client/shadereditor/moz.build
+++ b/devtools/client/shadereditor/moz.build
@@ -3,8 +3,11 @@
 # 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/.
 
 DevToolsModules(
     'panel.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: WebGL Shader Editor')
--- a/devtools/client/shared/moz.build
+++ b/devtools/client/shared/moz.build
@@ -48,8 +48,14 @@ DevToolsModules(
     'suggestion-picker.js',
     'telemetry.js',
     'theme.js',
     'undo.js',
     'view-source.js',
     'webgl-utils.js',
     'zoom-keys.js',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools')
+
+with Files('components/**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Shared Components')
--- a/devtools/client/sourceeditor/moz.build
+++ b/devtools/client/sourceeditor/moz.build
@@ -11,8 +11,11 @@ DIRS += [
 DevToolsModules(
     'autocomplete.js',
     'css-autocompleter.js',
     'debugger.js',
     'editor.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Source Editor')
--- a/devtools/client/storage/moz.build
+++ b/devtools/client/storage/moz.build
@@ -5,8 +5,11 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 DevToolsModules(
     'panel.js',
     'ui.js'
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Storage Inspector')
--- a/devtools/client/styleeditor/moz.build
+++ b/devtools/client/styleeditor/moz.build
@@ -8,8 +8,11 @@ BROWSER_CHROME_MANIFESTS += ['test/brows
 
 DevToolsModules(
     'styleeditor-commands.js',
     'styleeditor-panel.js',
     'StyleEditorUI.jsm',
     'StyleEditorUtil.jsm',
     'StyleSheetEditor.jsm',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Style Editor')
--- a/devtools/client/webaudioeditor/moz.build
+++ b/devtools/client/webaudioeditor/moz.build
@@ -3,8 +3,11 @@
 # 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/.
 
 DevToolsModules(
     'panel.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Web Audio Editor')
--- a/devtools/client/webconsole/moz.build
+++ b/devtools/client/webconsole/moz.build
@@ -16,8 +16,11 @@ DevToolsModules(
     'console-output.js',
     'hudservice.js',
     'jsterm.js',
     'panel.js',
     'utils.js',
     'webconsole-connection-proxy.js',
     'webconsole.js',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Console')
--- a/devtools/client/webide/moz.build
+++ b/devtools/client/webide/moz.build
@@ -16,8 +16,11 @@ BROWSER_CHROME_MANIFESTS += [
 ]
 MOCHITEST_CHROME_MANIFESTS += [
     'test/chrome.ini'
 ]
 
 JS_PREFERENCE_PP_FILES += [
     'webide-prefs.js',
 ]
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: WebIDE')
--- a/devtools/moz.build
+++ b/devtools/moz.build
@@ -18,8 +18,29 @@ DIRS += [
 ]
 
 # /browser uses DIST_SUBDIR.  We opt-in to this treatment when building
 # DevTools for the browser to keep the root omni.ja slim for use by external XUL
 # apps.  Mulet also uses this since it includes /browser.
 if CONFIG['MOZ_BUILD_APP'] in ('browser', 'b2g/dev'):
     DIST_SUBDIR = 'browser'
     export('DIST_SUBDIR')
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools')
+
+with Files('docs/**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools')
+
+with Files('docs/memory-panel.md'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Memory')
+
+with Files('docs/debugger-panel.md'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Debugger')
+
+with Files('docs/debugger-api.md'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Debugger')
+
+with Files('docs/http-inspector.md'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Console')
+
+with Files('docs/inspector-panel.md'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Inspector')
--- a/devtools/server/actors/moz.build
+++ b/devtools/server/actors/moz.build
@@ -65,8 +65,53 @@ DevToolsModules(
     'webbrowser.js',
     'webconsole.js',
     'webextension-inspected-window.js',
     'webextension.js',
     'webgl.js',
     'worker-list.js',
     'worker.js',
 )
+
+with Files('animation.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Animation Inspector')
+
+with Files('breakpoint.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Debugger')
+
+with Files('css-properties.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: CSS Rules Inspector')
+
+with Files('csscoverage.js'):
+    BUG_COMPONENT = ('Firefox', 'Graphics Commandline and Toolbar')
+
+with Files('inspector.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Inspector')
+
+with Files('memory.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Memory')
+
+with Files('monitor.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools')
+
+with Files('performance*'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Performance Tools (Profiler/Timeline)')
+
+with Files('profiler.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Performance Tools (Profiler/Timeline)')
+
+with Files('source.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Debugger')
+
+with Files('storage.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Storage Inspector')
+
+with Files('styleeditor.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Style Editor')
+
+with Files('webaudio.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Web Audio Editor')
+
+with Files('webconsole.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Console')
+
+with Files('webgl.js'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: WebGL Shader Editor')
--- a/devtools/server/moz.build
+++ b/devtools/server/moz.build
@@ -35,8 +35,11 @@ DevToolsModules(
     'css-logic.js',
     'event-parsers.js',
     'main.js',
     'primitive.js',
     'service-worker-child.js',
     'websocket-server.js',
     'worker.js'
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools')
--- a/devtools/server/performance/moz.build
+++ b/devtools/server/performance/moz.build
@@ -6,8 +6,11 @@
 
 DevToolsModules(
     'framerate.js',
     'memory.js',
     'profiler.js',
     'recorder.js',
     'timeline.js',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Performance Tools (Profiler/Timeline)')
--- a/devtools/shared/moz.build
+++ b/devtools/shared/moz.build
@@ -60,8 +60,11 @@ DevToolsModules(
     'Parser.jsm',
     'path.js',
     'plural-form.js',
     'protocol.js',
     'system.js',
     'task.js',
     'ThreadSafeDevToolsUtils.js',
 )
+
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools')
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8918,17 +8918,17 @@ nsGlobalWindow::EnterModalState()
     nsIPresShell::SetCapturingContent(nullptr, 0);
   }
 
   if (topWin->mModalStateDepth == 0) {
     NS_ASSERTION(!topWin->mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
 
     topWin->mSuspendedDoc = topDoc;
     if (topDoc) {
-      topDoc->SuppressEventHandling(nsIDocument::eAnimationsOnly);
+      topDoc->SuppressEventHandling(nsIDocument::eEvents);
     }
 
     nsGlobalWindow* inner = topWin->GetCurrentInnerWindowInternal();
     if (inner) {
       topWin->GetCurrentInnerWindowInternal()->Suspend();
     }
   }
   topWin->mModalStateDepth++;
@@ -8955,17 +8955,17 @@ nsGlobalWindow::LeaveModalState()
 
   if (topWin->mModalStateDepth == 0) {
     if (inner) {
       inner->Resume();
     }
 
     if (topWin->mSuspendedDoc) {
       nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
-      topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly,
+      topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents,
                                                                   currentDoc == topWin->mSuspendedDoc);
       topWin->mSuspendedDoc = nullptr;
     }
   }
 
   // Remember the time of the last dialog quit.
   if (inner) {
     inner->mLastDialogQuitTime = TimeStamp::Now();
@@ -10646,17 +10646,17 @@ nsGlobalWindow::GetSessionStorage(ErrorR
     nsresult rv;
 
     nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(docShell, &rv);
     if (NS_FAILED(rv)) {
       aError.Throw(rv);
       return nullptr;
     }
 
-    MOZ_DIAGNOSTIC_ASSERT((principal->GetPrivateBrowsingId() > 0) == IsPrivateBrowsing());
+    MOZ_ASSERT_IF(!mIsChrome, (principal->GetPrivateBrowsingId() > 0) == IsPrivateBrowsing());
 
     nsCOMPtr<nsIDOMStorage> storage;
     aError = storageManager->CreateStorage(AsInner(), principal, documentURI,
                                            getter_AddRefs(storage));
     if (aError.Failed()) {
       return nullptr;
     }
 
--- a/dom/base/test/test_viewsource_forbidden_in_object.html
+++ b/dom/base/test/test_viewsource_forbidden_in_object.html
@@ -28,31 +28,19 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   var testCaseIndex = -1;
   testCases = [
     {
       desc: "Test 1: view-source should not be allowed in an object.",
       URI: "view-source:file_general_document.html"
     },
     {
-      desc: "Test 2: feed:view-source should not be allowed in an object.",
-      URI: "feed:view-source:file_general_document.html"
-    },
-    {
-      desc: "Test 3: jar:view-source should not be allowed in an object",
+      desc: "Test 2: jar:view-source should not be allowed in an object",
       URI: "jar:view-source:file_general_document.html/!/"
     },
-    {
-      desc: "Test 4: pcast:view-source should not be allowed in an object",
-      URI: "pcast:view-source:file_general_document.html"
-    },
-    {
-      desc: "Test 5: pcast:feed:view-source should not be allowed in an object",
-      URI: "pcast:feed:view-source:file_general_document.html"
-    }
   ];
 
   function runNextTest() {
     ++testCaseIndex;
     if (testCaseIndex == testCases.length) {
       SimpleTest.finish();
       return;
     }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4423,17 +4423,19 @@ def getHandleDefault(defaultValue):
 
 def handleDefaultStringValue(defaultValue, method):
     """
     Returns a string which ends up calling 'method' with a (char_t*, length)
     pair that sets this string default value.  This string is suitable for
     passing as the second argument of handleDefault; in particular it does not
     end with a ';'
     """
-    assert defaultValue.type.isDOMString() or defaultValue.type.isByteString()
+    assert (defaultValue.type.isDOMString() or
+            defaultValue.type.isUSVString() or
+            defaultValue.type.isByteString())
     return ("static const %(char_t)s data[] = { %(data)s };\n"
             "%(method)s(data, ArrayLength(data) - 1)") % {
                 'char_t': "char" if defaultValue.type.isByteString() else "char16_t",
                 'method': method,
                 'data': ", ".join(["'" + char + "'" for char in
                                    defaultValue.value] + ["0"])
             }
 
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -691,16 +691,19 @@ public:
   void PassUnionWithDefaultValue12(const UnrestrictedFloatOrString& arg);
   void PassUnionWithDefaultValue13(const UnrestrictedFloatOrString& arg);
   void PassUnionWithDefaultValue14(const DoubleOrByteString& arg);
   void PassUnionWithDefaultValue15(const DoubleOrByteString& arg);
   void PassUnionWithDefaultValue16(const DoubleOrByteString& arg);
   void PassUnionWithDefaultValue17(const DoubleOrSupportedType& arg);
   void PassUnionWithDefaultValue18(const DoubleOrSupportedType& arg);
   void PassUnionWithDefaultValue19(const DoubleOrSupportedType& arg);
+  void PassUnionWithDefaultValue20(const DoubleOrUSVString& arg);
+  void PassUnionWithDefaultValue21(const DoubleOrUSVString& arg);
+  void PassUnionWithDefaultValue22(const DoubleOrUSVString& arg);
 
   void PassNullableUnionWithDefaultValue1(const Nullable<DoubleOrString>& arg);
   void PassNullableUnionWithDefaultValue2(const Nullable<DoubleOrString>& arg);
   void PassNullableUnionWithDefaultValue3(const Nullable<DoubleOrString>& arg);
   void PassNullableUnionWithDefaultValue4(const Nullable<FloatOrString>& arg);
   void PassNullableUnionWithDefaultValue5(const Nullable<FloatOrString>& arg);
   void PassNullableUnionWithDefaultValue6(const Nullable<FloatOrString>& arg);
   void PassNullableUnionWithDefaultValue7(const Nullable<UnrestrictedDoubleOrString>& arg);
@@ -712,16 +715,20 @@ public:
   void PassNullableUnionWithDefaultValue13(const Nullable<DoubleOrByteString>& arg);
   void PassNullableUnionWithDefaultValue14(const Nullable<DoubleOrByteString>& arg);
   void PassNullableUnionWithDefaultValue15(const Nullable<DoubleOrByteString>& arg);
   void PassNullableUnionWithDefaultValue16(const Nullable<DoubleOrByteString>& arg);
   void PassNullableUnionWithDefaultValue17(const Nullable<DoubleOrSupportedType>& arg);
   void PassNullableUnionWithDefaultValue18(const Nullable<DoubleOrSupportedType>& arg);
   void PassNullableUnionWithDefaultValue19(const Nullable<DoubleOrSupportedType>& arg);
   void PassNullableUnionWithDefaultValue20(const Nullable<DoubleOrSupportedType>& arg);
+  void PassNullableUnionWithDefaultValue21(const Nullable<DoubleOrUSVString>& arg);
+  void PassNullableUnionWithDefaultValue22(const Nullable<DoubleOrUSVString>& arg);
+  void PassNullableUnionWithDefaultValue23(const Nullable<DoubleOrUSVString>& arg);
+  void PassNullableUnionWithDefaultValue24(const Nullable<DoubleOrUSVString>& arg);
 
   void PassSequenceOfUnions(const Sequence<OwningCanvasPatternOrCanvasGradient>&);
   void PassSequenceOfUnions2(JSContext*, const Sequence<OwningObjectOrLong>&);
   void PassVariadicUnion(const Sequence<OwningCanvasPatternOrCanvasGradient>&);
 
   void PassSequenceOfNullableUnions(const Sequence<Nullable<OwningCanvasPatternOrCanvasGradient>>&);
   void PassVariadicNullableUnion(const Sequence<Nullable<OwningCanvasPatternOrCanvasGradient>>&);
   void PassMozMapOfUnions(const MozMap<OwningCanvasPatternOrCanvasGradient>&);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -670,16 +670,19 @@ interface TestInterface {
   void passUnionWithDefaultValue12(optional (unrestricted float or DOMString) arg = 1);
   void passUnionWithDefaultValue13(optional (unrestricted float or DOMString) arg = Infinity);
   void passUnionWithDefaultValue14(optional (double or ByteString) arg = "");
   void passUnionWithDefaultValue15(optional (double or ByteString) arg = 1);
   void passUnionWithDefaultValue16(optional (double or ByteString) arg = 1.5);
   void passUnionWithDefaultValue17(optional (double or SupportedType) arg = "text/html");
   void passUnionWithDefaultValue18(optional (double or SupportedType) arg = 1);
   void passUnionWithDefaultValue19(optional (double or SupportedType) arg = 1.5);
+  void passUnionWithDefaultValue20(optional (double or USVString) arg = "abc");
+  void passUnionWithDefaultValue21(optional (double or USVString) arg = 1);
+  void passUnionWithDefaultValue22(optional (double or USVString) arg = 1.5);
 
   void passNullableUnionWithDefaultValue1(optional (double or DOMString)? arg = "");
   void passNullableUnionWithDefaultValue2(optional (double or DOMString)? arg = 1);
   void passNullableUnionWithDefaultValue3(optional (double or DOMString)? arg = null);
   void passNullableUnionWithDefaultValue4(optional (float or DOMString)? arg = "");
   void passNullableUnionWithDefaultValue5(optional (float or DOMString)? arg = 1);
   void passNullableUnionWithDefaultValue6(optional (float or DOMString)? arg = null);
   void passNullableUnionWithDefaultValue7(optional (unrestricted double or DOMString)? arg = "");
@@ -691,16 +694,20 @@ interface TestInterface {
   void passNullableUnionWithDefaultValue13(optional (double or ByteString)? arg = "");
   void passNullableUnionWithDefaultValue14(optional (double or ByteString)? arg = 1);
   void passNullableUnionWithDefaultValue15(optional (double or ByteString)? arg = 1.5);
   void passNullableUnionWithDefaultValue16(optional (double or ByteString)? arg = null);
   void passNullableUnionWithDefaultValue17(optional (double or SupportedType)? arg = "text/html");
   void passNullableUnionWithDefaultValue18(optional (double or SupportedType)? arg = 1);
   void passNullableUnionWithDefaultValue19(optional (double or SupportedType)? arg = 1.5);
   void passNullableUnionWithDefaultValue20(optional (double or SupportedType)? arg = null);
+  void passNullableUnionWithDefaultValue21(optional (double or USVString)? arg = "abc");
+  void passNullableUnionWithDefaultValue22(optional (double or USVString)? arg = 1);
+  void passNullableUnionWithDefaultValue23(optional (double or USVString)? arg = 1.5);
+  void passNullableUnionWithDefaultValue24(optional (double or USVString)? arg = null);
 
   void passSequenceOfUnions(sequence<(CanvasPattern or CanvasGradient)> arg);
   void passSequenceOfUnions2(sequence<(object or long)> arg);
   void passVariadicUnion((CanvasPattern or CanvasGradient)... arg);
 
   void passSequenceOfNullableUnions(sequence<(CanvasPattern or CanvasGradient)?> arg);
   void passVariadicNullableUnion((CanvasPattern or CanvasGradient)?... arg);
   void passMozMapOfUnions(MozMap<(CanvasPattern or CanvasGradient)> arg);
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -505,16 +505,19 @@ interface TestExampleInterface {
   void passUnionWithDefaultValue12(optional (unrestricted float or DOMString) arg = 1);
   void passUnionWithDefaultValue13(optional (unrestricted float or DOMString) arg = Infinity);
   void passUnionWithDefaultValue14(optional (double or ByteString) arg = "");
   void passUnionWithDefaultValue15(optional (double or ByteString) arg = 1);
   void passUnionWithDefaultValue16(optional (double or ByteString) arg = 1.5);
   void passUnionWithDefaultValue17(optional (double or SupportedType) arg = "text/html");
   void passUnionWithDefaultValue18(optional (double or SupportedType) arg = 1);
   void passUnionWithDefaultValue19(optional (double or SupportedType) arg = 1.5);
+  void passUnionWithDefaultValue20(optional (double or USVString) arg = "abc");
+  void passUnionWithDefaultValue21(optional (double or USVString) arg = 1);
+  void passUnionWithDefaultValue22(optional (double or USVString) arg = 1.5);
 
   void passNullableUnionWithDefaultValue1(optional (double or DOMString)? arg = "");
   void passNullableUnionWithDefaultValue2(optional (double or DOMString)? arg = 1);
   void passNullableUnionWithDefaultValue3(optional (double or DOMString)? arg = null);
   void passNullableUnionWithDefaultValue4(optional (float or DOMString)? arg = "");
   void passNullableUnionWithDefaultValue5(optional (float or DOMString)? arg = 1);
   void passNullableUnionWithDefaultValue6(optional (float or DOMString)? arg = null);
   void passNullableUnionWithDefaultValue7(optional (unrestricted double or DOMString)? arg = "");
@@ -526,16 +529,20 @@ interface TestExampleInterface {
   void passNullableUnionWithDefaultValue13(optional (double or ByteString)? arg = "");
   void passNullableUnionWithDefaultValue14(optional (double or ByteString)? arg = 1);
   void passNullableUnionWithDefaultValue15(optional (double or ByteString)? arg = 1.5);
   void passNullableUnionWithDefaultValue16(optional (double or ByteString)? arg = null);
   void passNullableUnionWithDefaultValue17(optional (double or SupportedType)? arg = "text/html");
   void passNullableUnionWithDefaultValue18(optional (double or SupportedType)? arg = 1);
   void passNullableUnionWithDefaultValue19(optional (double or SupportedType)? arg = 1.5);
   void passNullableUnionWithDefaultValue20(optional (double or SupportedType)? arg = null);
+  void passNullableUnionWithDefaultValue21(optional (double or USVString)? arg = "abc");
+  void passNullableUnionWithDefaultValue22(optional (double or USVString)? arg = 1);
+  void passNullableUnionWithDefaultValue23(optional (double or USVString)? arg = 1.5);
+  void passNullableUnionWithDefaultValue24(optional (double or USVString)? arg = null);
 
   void passSequenceOfUnions(sequence<(CanvasPattern or CanvasGradient)> arg);
   void passSequenceOfUnions2(sequence<(object or long)> arg);
   void passVariadicUnion((CanvasPattern or CanvasGradient)... arg);
 
   void passSequenceOfNullableUnions(sequence<(CanvasPattern or CanvasGradient)?> arg);
   void passVariadicNullableUnion((CanvasPattern or CanvasGradient)?... arg);
   void passMozMapOfUnions(MozMap<(CanvasPattern or CanvasGradient)> arg);
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -517,16 +517,19 @@ interface TestJSImplInterface {
   void passUnionWithDefaultValue12(optional (unrestricted float or DOMString) arg = 1);
   void passUnionWithDefaultValue13(optional (unrestricted float or DOMString) arg = Infinity);
   void passUnionWithDefaultValue14(optional (double or ByteString) arg = "");
   void passUnionWithDefaultValue15(optional (double or ByteString) arg = 1);
   void passUnionWithDefaultValue16(optional (double or ByteString) arg = 1.5);
   void passUnionWithDefaultValue17(optional (double or SupportedType) arg = "text/html");
   void passUnionWithDefaultValue18(optional (double or SupportedType) arg = 1);
   void passUnionWithDefaultValue19(optional (double or SupportedType) arg = 1.5);
+  void passUnionWithDefaultValue20(optional (double or USVString) arg = "abc");
+  void passUnionWithDefaultValue21(optional (double or USVString) arg = 1);
+  void passUnionWithDefaultValue22(optional (double or USVString) arg = 1.5);
 
   void passNullableUnionWithDefaultValue1(optional (double or DOMString)? arg = "");
   void passNullableUnionWithDefaultValue2(optional (double or DOMString)? arg = 1);
   void passNullableUnionWithDefaultValue3(optional (double or DOMString)? arg = null);
   void passNullableUnionWithDefaultValue4(optional (float or DOMString)? arg = "");
   void passNullableUnionWithDefaultValue5(optional (float or DOMString)? arg = 1);
   void passNullableUnionWithDefaultValue6(optional (float or DOMString)? arg = null);
   void passNullableUnionWithDefaultValue7(optional (unrestricted double or DOMString)? arg = "");
@@ -538,16 +541,20 @@ interface TestJSImplInterface {
   void passNullableUnionWithDefaultValue13(optional (double or ByteString)? arg = "");
   void passNullableUnionWithDefaultValue14(optional (double or ByteString)? arg = 1);
   void passNullableUnionWithDefaultValue15(optional (double or ByteString)? arg = 1.5);
   void passNullableUnionWithDefaultValue16(optional (double or ByteString)? arg = null);
   void passNullableUnionWithDefaultValue17(optional (double or SupportedType)? arg = "text/html");
   void passNullableUnionWithDefaultValue18(optional (double or SupportedType)? arg = 1);
   void passNullableUnionWithDefaultValue19(optional (double or SupportedType)? arg = 1.5);
   void passNullableUnionWithDefaultValue20(optional (double or SupportedType)? arg = null);
+  void passNullableUnionWithDefaultValue21(optional (double or USVString)? arg = "abc");
+  void passNullableUnionWithDefaultValue22(optional (double or USVString)? arg = 1);
+  void passNullableUnionWithDefaultValue23(optional (double or USVString)? arg = 1.5);
+  void passNullableUnionWithDefaultValue24(optional (double or USVString)? arg = null);
 
   void passSequenceOfUnions(sequence<(CanvasPattern or CanvasGradient)> arg);
   void passSequenceOfUnions2(sequence<(object or long)> arg);
   void passVariadicUnion((CanvasPattern or CanvasGradient)... arg);
 
   void passSequenceOfNullableUnions(sequence<(CanvasPattern or CanvasGradient)?> arg);
   void passVariadicNullableUnion((CanvasPattern or CanvasGradient)?... arg);
   void passMozMapOfUnions(MozMap<(CanvasPattern or CanvasGradient)> arg);
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -168,26 +168,16 @@ WebGLShader::ShaderSource(const nsAStrin
 
     if (!ValidateGLSLPreprocString(mContext, funcName, sourceWithoutComments))
         return;
 
     // We checked that the source stripped of comments is in the
     // 7-bit ASCII range, so we can skip the NS_IsAscii() check.
     const NS_LossyConvertUTF16toASCII cleanSource(sourceWithoutComments);
 
-    if (mContext->gl->WorkAroundDriverBugs()) {
-        const size_t maxSourceLength = 0x3ffff;
-        if (cleanSource.Length() > maxSourceLength) {
-            mContext->ErrorInvalidValue("shaderSource: Source has more than %d"
-                                        " characters. (Driver workaround)",
-                                        maxSourceLength);
-            return;
-        }
-    }
-
     if (PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS")) {
         printf_stderr("////////////////////////////////////////\n");
         printf_stderr("// MOZ_WEBGL_DUMP_SHADERS:\n");
 
         // Wow - Roll Your Own Foreach-Lines because printf_stderr has a hard-coded
         // internal size, so long strings are truncated.
 
         const size_t maxChunkSize = 1024-1; // -1 for null-term.
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -354,19 +354,21 @@ TabParent::IsVisible() const
 
 void
 TabParent::DestroyInternal()
 {
   IMEStateManager::OnTabParentDestroying(this);
 
   RemoveWindowListeners();
 
+#ifdef ACCESSIBILITY
   if (a11y::DocAccessibleParent* tabDoc = GetTopLevelDocAccessible()) {
     tabDoc->Destroy();
   }
+#endif
 
   // If this fails, it's most likely due to a content-process crash,
   // and auto-cleanup will kick in.  Otherwise, the child side will
   // destroy itself and send back __delete__().
   Unused << SendDestroy();
 
   if (RenderFrameParent* frame = GetRenderFrame()) {
     RemoveTabParentFromTable(frame->GetLayersId());
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -1251,16 +1251,18 @@ void
 MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions)
 {
   MOZ_ASSERT(aEndBlockingDecisions >= mProcessedTime);
   // The next state computed time can be the same as the previous: it
   // means the driver would be have been blocking indefinitly, but the graph has
   // been woken up right after having been to sleep.
   MOZ_ASSERT(aEndBlockingDecisions >= mStateComputedTime);
 
+  UpdateStreamOrder();
+
   bool ensureNextIteration = false;
 
   // Grab pending stream input and compute blocking time
   for (MediaStream* stream : mStreams) {
     if (SourceMediaStream* is = stream->AsSourceStream()) {
       ExtractPendingInput(is, aEndBlockingDecisions, &ensureNextIteration);
     }
 
@@ -1401,32 +1403,17 @@ MediaStreamGraphImpl::UpdateMainThreadSt
 bool
 MediaStreamGraphImpl::OneIteration(GraphTime aStateEnd)
 {
   WebCore::DenormalDisabler disabler;
 
   // Process graph message from the main thread for this iteration.
   RunMessagesInQueue();
 
-  UpdateStreamOrder();
-
-  bool switchingFromSystemClockDriver = false;
-  {
-    MonitorAutoLock mon(mMonitor);
-    switchingFromSystemClockDriver = CurrentDriver()->AsSystemClockDriver() && CurrentDriver()->Switching();
-  }
-
   GraphTime stateEnd = std::min(aStateEnd, mEndTime);
-
-  // See Bug 1228226 - If we're switching from the SystemClockDriver, we
-  // don't want time to advance until after the switch.
-  if (switchingFromSystemClockDriver) {
-    stateEnd = mProcessedTime;
-  }
-
   UpdateGraph(stateEnd);
 
   mStateComputedTime = stateEnd;
 
   Process();
 
   GraphTime oldProcessedTime = mProcessedTime;
   mProcessedTime = stateEnd;
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -294,22 +294,19 @@ GMPChild::GetAPI(const char* aAPIName,
 mozilla::ipc::IPCResult
 GMPChild::RecvPreloadLibs(const nsCString& aLibs)
 {
 #ifdef XP_WIN
   // Pre-load DLLs that need to be used by the EME plugin but that can't be
   // loaded after the sandbox has started
   // Items in this must be lowercase!
   static const char *const whitelist[] = {
-    "d3d9.dll", // Create an `IDirect3D9` to get adapter information
     "dxva2.dll", // Get monitor information
     "evr.dll", // MFGetStrideForBitmapInfoHeader
     "mfplat.dll", // MFCreateSample, MFCreateAlignedMemoryBuffer, MFCreateMediaType
-    "msauddecmft.dll", // AAC decoder (on Windows 8)
-    "msmpeg2adec.dll", // AAC decoder (on Windows 7)
     "msmpeg2vdec.dll", // H.264 decoder
   };
 
   nsTArray<nsCString> libs;
   SplitAt(", ", aLibs, libs);
   for (nsCString lib : libs) {
     ToLowerCase(lib);
     for (const char* whiteListedLib : whitelist) {
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -953,32 +953,64 @@ GMPParent::ParseChromiumManifest(const n
                                  m.mX_cdm_host_versions.ToInteger(&ignored))) {
     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   mDisplayName = NS_ConvertUTF16toUTF8(m.mName);
   mDescription = NS_ConvertUTF16toUTF8(m.mDescription);
   mVersion = NS_ConvertUTF16toUTF8(m.mVersion);
 
+  nsCString kEMEKeySystem;
+
+  // We hard code a few of the settings because they can't be stored in the
+  // widevine manifest without making our API different to widevine's.
+  if (mDisplayName.EqualsASCII("clearkey")) {
+    kEMEKeySystem = kEMEKeySystemClearkey;
+#if XP_WIN
+    mLibs = NS_LITERAL_CSTRING("dxva2.dll, msmpeg2vdec.dll, evr.dll, mfh264dec.dll, mfplat.dll");
+#endif
+  } else if (mDisplayName.EqualsASCII("WidevineCdm")) {
+    kEMEKeySystem = kEMEKeySystemWidevine;
+#if XP_WIN
+    mLibs = NS_LITERAL_CSTRING("dxva2.dll");
+#endif
+  } else {
+    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  }
+
   GMPCapability video(NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER));
-  video.mAPITags.AppendElement(NS_LITERAL_CSTRING("h264"));
-  video.mAPITags.AppendElement(NS_LITERAL_CSTRING("vp8"));
-  video.mAPITags.AppendElement(NS_LITERAL_CSTRING("vp9"));
-  video.mAPITags.AppendElement(kEMEKeySystemWidevine);
+
+  nsCString codecsString = NS_ConvertUTF16toUTF8(m.mX_cdm_codecs);
+  nsTArray<nsCString> codecs;
+  SplitAt(",", codecsString, codecs);
+
+  for (const nsCString& chromiumCodec : codecs) {
+    nsCString codec;
+    if (chromiumCodec.EqualsASCII("vp8")) {
+      codec = NS_LITERAL_CSTRING("vp8");
+    } else if (chromiumCodec.EqualsASCII("vp9.0")) {
+      codec = NS_LITERAL_CSTRING("vp9");
+    } else if (chromiumCodec.EqualsASCII("avc1")) {
+      codec = NS_LITERAL_CSTRING("h264");
+    } else {
+      return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    }
+
+    video.mAPITags.AppendElement(codec);
+  }
+
+  video.mAPITags.AppendElement(kEMEKeySystem);
   mCapabilities.AppendElement(Move(video));
 
   GMPCapability decrypt(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR));
-  decrypt.mAPITags.AppendElement(kEMEKeySystemWidevine);
+
+  decrypt.mAPITags.AppendElement(kEMEKeySystem);
   mCapabilities.AppendElement(Move(decrypt));
 
-  MOZ_ASSERT(mName.EqualsLiteral("widevinecdm"));
   mAdapter = NS_LITERAL_STRING("widevine");
-#ifdef XP_WIN
-  mLibs = NS_LITERAL_CSTRING("dxva2.dll");
-#endif
 
   return GenericPromise::CreateAndResolve(true, __func__);
 }
 
 bool
 GMPParent::CanBeSharedCrossNodeIds() const
 {
   return !mAsyncShutdownInProgress &&
--- a/dom/media/gmp/moz.build
+++ b/dom/media/gmp/moz.build
@@ -67,16 +67,17 @@ EXPORTS += [
     'GMPVideoDecoderProxy.h',
     'GMPVideoEncodedFrameImpl.h',
     'GMPVideoEncoderChild.h',
     'GMPVideoEncoderParent.h',
     'GMPVideoEncoderProxy.h',
     'GMPVideoHost.h',
     'GMPVideoi420FrameImpl.h',
     'GMPVideoPlaneImpl.h',
+    'widevine-adapter/content_decryption_module.h',
 ]
 
 # We link GMPLoader into xul on Android and Linux as its code does not
 # need to be covered by a DRM vendor's voucher.
 if CONFIG['OS_ARCH'] == 'Linux':
     SOURCES += [
       'GMPLoader.cpp',
     ]
@@ -114,17 +115,17 @@ UNIFIED_SOURCES += [
     'GMPUtils.cpp',
     'GMPVideoDecoderChild.cpp',
     'GMPVideoDecoderParent.cpp',
     'GMPVideoEncodedFrameImpl.cpp',
     'GMPVideoEncoderChild.cpp',
     'GMPVideoEncoderParent.cpp',
     'GMPVideoHost.cpp',
     'GMPVideoi420FrameImpl.cpp',
-    'GMPVideoPlaneImpl.cpp',
+    'GMPVideoPlaneImpl.cpp'
 ]
 
 DIRS += [
     'rlz',
     'widevine-adapter',
 ]
 
 IPDL_SOURCES += [
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
@@ -308,16 +308,27 @@ void
 WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId,
                                               const char* aSessionId,
                                               uint32_t aSessionIdSize)
 {
   if (!mCallback) {
     Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) FAIL; !mCallback", aPromiseId);
     return;
   }
+
+  // This is laid out in the API. If we fail to load a session we should
+  // call OnResolveNewSessionPromise with nullptr as the sessionId.
+  // We can safely assume this means that we have failed to load a session
+  // as the other methods specify calling 'OnRejectPromise' when they fail.
+  if (!aSessionId) {
+    Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) Failed to load session", aPromiseId);
+    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
+    return;
+  }
+
   Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d)", aPromiseId);
   auto iter = mPromiseIdToNewSessionTokens.find(aPromiseId);
   if (iter == mPromiseIdToNewSessionTokens.end()) {
     Log("FAIL: Decryptor::OnResolveNewSessionPromise(aPromiseId=%d) unknown aPromiseId", aPromiseId);
     return;
   }
   mCallback->SetSessionId(iter->second, aSessionId, aSessionIdSize);
   mCallback->ResolvePromise(aPromiseId);
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -16,16 +16,19 @@ support-files =
 disabled = Does not reliably pass on 32-bit systems - bug 1314098
 skip-if = !e10s
 [browser_autofocus_background.js]
 [browser_autofocus_preference.js]
 [browser_bug396843.js]
 [browser_bug1004814.js]
 [browser_bug1008941_dismissGeolocationHanger.js]
 [browser_bug1238427.js]
+[browser_cancel_keydown_keypress_event.js]
+support-files =
+  prevent_return_key.html
 [browser_ConsoleAPI_originAttributes.js]
 [browser_ConsoleAPITests.js]
 skip-if = e10s
 [browser_ConsoleStorageAPITests.js]
 [browser_ConsoleStoragePBTest_perwindowpb.js]
 [browser_focus_steal_from_chrome.js]
 [browser_focus_steal_from_chrome_during_mousedown.js]
 [browser_frame_elements.js]
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/browser_cancel_keydown_keypress_event.js
@@ -0,0 +1,41 @@
+const URL =
+  "https://example.com/browser/dom/tests/browser/prevent_return_key.html";
+
+// Wait for alert dialog and dismiss it immediately.
+function awaitAndCloseAlertDialog() {
+  return new Promise(resolve => {
+    function onDialogShown(node) {
+      Services.obs.removeObserver(onDialogShown, "tabmodal-dialog-loaded");
+      let button = node.ui.button0;
+      button.click();
+      resolve();
+    }
+    Services.obs.addObserver(onDialogShown, "tabmodal-dialog-loaded");
+  });
+}
+
+add_task(function* () {
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
+  let browser = tab.linkedBrowser;
+
+  // Focus and enter random text on input.
+  yield ContentTask.spawn(browser, null, function* () {
+    let input = content.document.getElementById("input");
+    input.focus();
+    input.value = "abcd";
+  });
+
+  // Send return key (cross process) to submit the form implicitly.
+  let dialogShown = awaitAndCloseAlertDialog();
+  EventUtils.synthesizeKey("VK_RETURN", {});
+  yield dialogShown;
+
+  // Check that the form should not have been submitted.
+  yield ContentTask.spawn(browser, null, function* () {
+    let result = content.document.getElementById("result").innerHTML;
+    info("submit result: " + result);
+    is(result, "not submitted", "form should not have submitted");
+  });
+
+  gBrowser.removeCurrentTab();
+});
new file mode 100644
--- /dev/null
+++ b/dom/tests/browser/prevent_return_key.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Prevent return key should not submit form</title>
+  <script type="application/javascript">
+  function init() {
+    let input = document.getElementById("input");
+    input.addEventListener("keydown", function(aEvent) {
+      input.removeEventListener("keydown", arguments.callee);
+      if (aEvent.keyCode == 13) { // return key
+        alert("Hello!");
+        aEvent.preventDefault();
+        return false;
+      }
+    });
+
+    let form = document.getElementById("form");
+    form.addEventListener("submit", function() {
+      form.removeEventListener("submit", arguments.callee);
+      let result = document.getElementById("result");
+      result.innerHTML = "submitted";
+    });
+  }
+  </script>
+</head>
+
+<body onload="init()">
+  <form id="form">
+    <input type="text" id="input">
+    <button type="submit" id="submitBtn">Submit</button>
+  </form>
+  <p id="result">not submitted</p>
+</body>
+</html>
+
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -147,19 +147,16 @@ partial interface Document {
   //(HTML only)DOMString queryCommandValue(DOMString commandId);
   //(Not implemented)readonly attribute HTMLCollection commands;
 
   // special event handler IDL attributes that only apply to Document objects
   [LenientThis] attribute EventHandler onreadystatechange;
 
   // Gecko extensions?
                 attribute EventHandler onwheel;
-                attribute EventHandler oncopy;
-                attribute EventHandler oncut;
-                attribute EventHandler onpaste;
                 attribute EventHandler onbeforescriptexecute;
                 attribute EventHandler onafterscriptexecute;
 
                 [Pref="dom.select_events.enabled"]
                 attribute EventHandler onselectionchange;
 
   /**
    * True if this document is synthetic : stand alone image, video, audio file,
@@ -440,13 +437,14 @@ partial interface Document {
 // and whether inline scripts are blocked by the document's CSP.
 partial interface Document {
   [Func="IsChromeOrXBL"] readonly attribute boolean hasScriptsBlockedBySandbox;
   [Func="IsChromeOrXBL"] readonly attribute boolean inlineScriptAllowedByCSP;
 };
 
 Document implements XPathEvaluator;
 Document implements GlobalEventHandlers;
+Document implements DocumentAndElementEventHandlers;
 Document implements TouchEventHandlers;
 Document implements ParentNode;
 Document implements OnErrorEventHandlerForNodes;
 Document implements GeometryUtils;
 Document implements FontFaceSource;
--- a/dom/webidl/EventHandler.webidl
+++ b/dom/webidl/EventHandler.webidl
@@ -156,16 +156,23 @@ interface WindowEventHandlers {
            attribute EventHandler ononline;
            attribute EventHandler onpagehide;
            attribute EventHandler onpageshow;
            attribute EventHandler onpopstate;
            attribute EventHandler onstorage;
            attribute EventHandler onunload;
 };
 
+[NoInterfaceObject]
+interface DocumentAndElementEventHandlers {
+  attribute EventHandler oncopy;
+  attribute EventHandler oncut;
+  attribute EventHandler onpaste;
+};
+
 // The spec has |attribute OnErrorEventHandler onerror;| on
 // GlobalEventHandlers, and calls the handler differently depending on
 // whether an ErrorEvent was fired. We don't do that, and until we do we'll
 // need to distinguish between onerror on Window or on nodes.
 
 [NoInterfaceObject]
 interface OnErrorEventHandlerForNodes {
            attribute EventHandler onerror;
--- a/dom/webidl/HTMLElement.webidl
+++ b/dom/webidl/HTMLElement.webidl
@@ -61,21 +61,16 @@ interface HTMLElement : Element {
   //readonly attribute DOMString? commandIcon;
   //readonly attribute boolean? commandHidden;
   //readonly attribute boolean? commandDisabled;
   //readonly attribute boolean? commandChecked;
 
   // styling
   [PutForwards=cssText, Constant]
   readonly attribute CSSStyleDeclaration style;
-
-  // Mozilla specific stuff
-           attribute EventHandler oncopy;
-           attribute EventHandler oncut;
-           attribute EventHandler onpaste;
 };
 
 // http://dev.w3.org/csswg/cssom-view/#extensions-to-the-htmlelement-interface
 partial interface HTMLElement {
   // CSSOM things are not [Pure] because they can flush
   readonly attribute Element? offsetParent;
   readonly attribute long offsetTop;
   readonly attribute long offsetLeft;
@@ -98,12 +93,13 @@ interface TouchEventHandlers {
            attribute EventHandler ontouchend;
   [Func="nsGenericHTMLElement::TouchEventsEnabled"]
            attribute EventHandler ontouchmove;
   [Func="nsGenericHTMLElement::TouchEventsEnabled"]
            attribute EventHandler ontouchcancel;
 };
 
 HTMLElement implements GlobalEventHandlers;
+HTMLElement implements DocumentAndElementEventHandlers;
 HTMLElement implements TouchEventHandlers;
 HTMLElement implements OnErrorEventHandlerForNodes;
 
 interface HTMLUnknownElement : HTMLElement {};
--- a/dom/webidl/SVGElement.webidl
+++ b/dom/webidl/SVGElement.webidl
@@ -17,21 +17,18 @@ interface SVGElement : Element {
   readonly attribute SVGAnimatedString className;
   [SameObject] readonly attribute DOMStringMap dataset;
   [PutForwards=cssText, Constant]
   readonly attribute CSSStyleDeclaration style;
 
   readonly attribute SVGSVGElement? ownerSVGElement;
   readonly attribute SVGElement? viewportElement;
 
-  attribute EventHandler oncopy;
-  attribute EventHandler oncut;
-  attribute EventHandler onpaste;
-
   [SetterThrows, Pure]
         attribute long tabIndex;
   [Throws] void focus();
   [Throws] void blur();
 };
 
 SVGElement implements GlobalEventHandlers;
+SVGElement implements DocumentAndElementEventHandlers;
 SVGElement implements TouchEventHandlers;
 SVGElement implements OnErrorEventHandlerForNodes;
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -241,45 +241,94 @@ ServiceWorkerManager::ServiceWorkerManag
 ServiceWorkerManager::~ServiceWorkerManager()
 {
   // The map will assert if it is not empty when destroyed.
   mRegistrationInfos.Clear();
   MOZ_ASSERT(!mActor);
 }
 
 void
-ServiceWorkerManager::Init()
+ServiceWorkerManager::Init(ServiceWorkerRegistrar* aRegistrar)
 {
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     DebugOnly<nsresult> rv;
     rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false /* ownsWeak */);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   if (XRE_IsParentProcess()) {
-    RefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
-    MOZ_ASSERT(swr);
+    MOZ_DIAGNOSTIC_ASSERT(aRegistrar);
 
     nsTArray<ServiceWorkerRegistrationData> data;
-    swr->GetRegistrations(data);
+    aRegistrar->GetRegistrations(data);
     LoadRegistrations(data);
 
     if (obs) {
       DebugOnly<nsresult> rv;
       rv = obs->AddObserver(this, PURGE_SESSION_HISTORY, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
       rv = obs->AddObserver(this, PURGE_DOMAIN_DATA, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
       rv = obs->AddObserver(this, CLEAR_ORIGIN_DATA, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 }
 
+void
+ServiceWorkerManager::MaybeStartShutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mShuttingDown) {
+    return;
+  }
+
+  mShuttingDown = true;
+
+  for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
+    for (auto it2 = it1.UserData()->mUpdateTimers.Iter(); !it2.Done(); it2.Next()) {
+      nsCOMPtr<nsITimer> timer = it2.UserData();
+      timer->Cancel();
+    }
+    it1.UserData()->mUpdateTimers.Clear();
+
+    for (auto it2 = it1.UserData()->mJobQueues.Iter(); !it2.Done(); it2.Next()) {
+      RefPtr<ServiceWorkerJobQueue> queue = it2.UserData();
+      queue->CancelAll();
+    }
+    it1.UserData()->mJobQueues.Clear();
+  }
+
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+
+    if (XRE_IsParentProcess()) {
+      obs->RemoveObserver(this, PURGE_SESSION_HISTORY);
+      obs->RemoveObserver(this, PURGE_DOMAIN_DATA);
+      obs->RemoveObserver(this, CLEAR_ORIGIN_DATA);
+    }
+  }
+
+  mPendingOperations.Clear();
+
+  if (!mActor) {
+    return;
+  }
+
+  mActor->ManagerShuttingDown();
+
+  RefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
+  nsresult rv = NS_DispatchToMainThread(runnable);
+  Unused << NS_WARN_IF(NS_FAILED(rv));
+  mActor = nullptr;
+}
+
 class ServiceWorkerResolveWindowPromiseOnRegisterCallback final : public ServiceWorkerJob::Callback
 {
   RefPtr<nsPIDOMWindowInner> mWindow;
   // The promise "returned" by the call to Update up to
   // navigator.serviceWorker.register().
   RefPtr<Promise> mPromise;
 
   ~ServiceWorkerResolveWindowPromiseOnRegisterCallback()
@@ -1353,22 +1402,33 @@ ServiceWorkerManager::GetOrCreateJobQueu
 /* static */
 already_AddRefed<ServiceWorkerManager>
 ServiceWorkerManager::GetInstance()
 {
   // Note: We don't simply check gInstance for null-ness here, since otherwise
   // this can resurrect the ServiceWorkerManager pretty late during shutdown.
   static bool firstTime = true;
   if (firstTime) {
+    RefPtr<ServiceWorkerRegistrar> swr;
+
+    // Don't create the ServiceWorkerManager until the ServiceWorkerRegistrar is
+    // initialized.
+    if (XRE_IsParentProcess()) {
+      swr = ServiceWorkerRegistrar::Get();
+      if (!swr) {
+        return nullptr;
+      }
+    }
+
     firstTime = false;
 
     AssertIsOnMainThread();
 
     gInstance = new ServiceWorkerManager();
-    gInstance->Init();
+    gInstance->Init(swr);
     ClearOnShutdown(&gInstance);
   }
   RefPtr<ServiceWorkerManager> copy = gInstance.get();
   return copy.forget();
 }
 
 void
 ServiceWorkerManager::FinishFetch(ServiceWorkerRegistrationInfo* aRegistration)
@@ -1736,32 +1796,37 @@ ServiceWorkerManager::LoadRegistrations(
   for (uint32_t i = 0, len = aRegistrations.Length(); i < len; ++i) {
     LoadRegistration(aRegistrations[i]);
   }
 }
 
 void
 ServiceWorkerManager::ActorFailed()
 {
-  MOZ_CRASH("Failed to create a PBackgroundChild actor!");
+  MOZ_DIAGNOSTIC_ASSERT(!mActor);
+  MaybeStartShutdown();
 }
 
 void
 ServiceWorkerManager::ActorCreated(mozilla::ipc::PBackgroundChild* aActor)
 {
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(!mActor);
 
   if (mShuttingDown) {
-    mPendingOperations.Clear();
+    MOZ_DIAGNOSTIC_ASSERT(mPendingOperations.IsEmpty());
     return;
   }
 
   PServiceWorkerManagerChild* actor =
     aActor->SendPServiceWorkerManagerConstructor();
+  if (!actor) {
+    ActorFailed();
+    return;
+  }
 
   mActor = static_cast<ServiceWorkerManagerChild*>(actor);
 
   // Flush the pending requests.
   for (uint32_t i = 0, len = mPendingOperations.Length(); i < len; ++i) {
     MOZ_ASSERT(mPendingOperations[i]);
     nsresult rv = NS_DispatchToCurrentThread(mPendingOperations[i].forget());
     if (NS_FAILED(rv)) {
@@ -1779,17 +1844,20 @@ ServiceWorkerManager::StoreRegistration(
 {
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aRegistration);
 
   if (mShuttingDown) {
     return;
   }
 
-  MOZ_ASSERT(mActor);
+  MOZ_DIAGNOSTIC_ASSERT(mActor);
+  if (!mActor) {
+    return;
+  }
 
   ServiceWorkerRegistrationData data;
   nsresult rv = PopulateRegistrationData(aPrincipal, aRegistration, data);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   PrincipalInfo principalInfo;
@@ -3554,53 +3622,17 @@ ServiceWorkerManager::Observe(nsISupport
     OriginAttributesPattern pattern;
     MOZ_ALWAYS_TRUE(pattern.Init(nsAutoString(aData)));
 
     RemoveAllRegistrations(&pattern);
     return NS_OK;
   }
 
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
-    mShuttingDown = true;
-
-    for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
-      for (auto it2 = it1.UserData()->mUpdateTimers.Iter(); !it2.Done(); it2.Next()) {
-        nsCOMPtr<nsITimer> timer = it2.UserData();
-        timer->Cancel();
-      }
-      it1.UserData()->mUpdateTimers.Clear();
-
-      for (auto it2 = it1.UserData()->mJobQueues.Iter(); !it2.Done(); it2.Next()) {
-        RefPtr<ServiceWorkerJobQueue> queue = it2.UserData();
-        queue->CancelAll();
-      }
-      it1.UserData()->mJobQueues.Clear();
-    }
-
-    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-    if (obs) {
-      obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
-
-      if (XRE_IsParentProcess()) {
-        obs->RemoveObserver(this, PURGE_SESSION_HISTORY);
-        obs->RemoveObserver(this, PURGE_DOMAIN_DATA);
-        obs->RemoveObserver(this, CLEAR_ORIGIN_DATA);
-      }
-    }
-
-    if (mActor) {
-      mActor->ManagerShuttingDown();
-
-      RefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
-      nsresult rv = NS_DispatchToMainThread(runnable);
-      Unused << NS_WARN_IF(NS_FAILED(rv));
-      mActor = nullptr;
-    } else {
-      mPendingOperations.Clear();
-    }
+    MaybeStartShutdown();
     return NS_OK;
   }
 
   MOZ_CRASH("Received message we aren't supposed to be registered for!");
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -36,16 +36,17 @@
 class nsIConsoleReportCollector;
 
 namespace mozilla {
 
 class OriginAttributes;
 
 namespace dom {
 
+class ServiceWorkerRegistrar;
 class ServiceWorkerRegistrationListener;
 
 namespace workers {
 
 class ServiceWorkerClientInfo;
 class ServiceWorkerInfo;
 class ServiceWorkerJobQueue;
 class ServiceWorkerManagerChild;
@@ -323,17 +324,20 @@ public:
   void
   WorkerIsIdle(ServiceWorkerInfo* aWorker);
 
 private:
   ServiceWorkerManager();
   ~ServiceWorkerManager();
 
   void
-  Init();
+  Init(ServiceWorkerRegistrar* aRegistrar);
+
+  void
+  MaybeStartShutdown();
 
   already_AddRefed<ServiceWorkerJobQueue>
   GetOrCreateJobQueue(const nsACString& aOriginSuffix,
                       const nsACString& aScope);
 
   void
   MaybeRemoveRegistrationInfo(const nsACString& aScopeKey);
 
--- a/dom/workers/ServiceWorkerManagerParent.cpp
+++ b/dom/workers/ServiceWorkerManagerParent.cpp
@@ -39,17 +39,22 @@ public:
   NS_IMETHOD
   Run() override
   {
     AssertIsInMainProcess();
     AssertIsOnBackgroundThread();
 
     RefPtr<dom::ServiceWorkerRegistrar> service =
       dom::ServiceWorkerRegistrar::Get();
-    MOZ_ASSERT(service);
+
+    // Shutdown during the process of trying to update the registrar.  Give
+    // up on this modification.
+    if (!service) {
+      return NS_OK;
+    }
 
     service->RegisterServiceWorker(mData);
 
     RefPtr<ServiceWorkerManagerService> managerService =
       ServiceWorkerManagerService::Get();
     if (managerService) {
       managerService->PropagateRegistration(mParentID, mData);
     }
@@ -79,17 +84,22 @@ public:
   NS_IMETHOD
   Run() override
   {
     AssertIsInMainProcess();
     AssertIsOnBackgroundThread();
 
     RefPtr<dom::ServiceWorkerRegistrar> service =
       dom::ServiceWorkerRegistrar::Get();
-    MOZ_ASSERT(service);
+
+    // Shutdown during the process of trying to update the registrar.  Give
+    // up on this modification.
+    if (!service) {
+      return NS_OK;
+    }
 
     service->UnregisterServiceWorker(mPrincipalInfo,
                                      NS_ConvertUTF16toUTF8(mScope));
 
     RefPtr<ServiceWorkerManagerService> managerService =
       ServiceWorkerManagerService::Get();
     if (managerService) {
       managerService->PropagateUnregister(mParentID, mPrincipalInfo,
--- a/editor/moz.build
+++ b/editor/moz.build
@@ -37,8 +37,11 @@ XPIDL_MODULE = 'editor'
 
 EXPORTS += [
     'nsEditorCID.h',
 ]
 
 EXTRA_JS_MODULES += [
     'AsyncSpellCheckTestHelper.jsm',
 ]
+
+with Files('**'):
+    BUG_COMPONENT = ('Core', 'Editor')
--- a/gfx/skia/skia/src/core/SkScan_Path.cpp
+++ b/gfx/skia/skia/src/core/SkScan_Path.cpp
@@ -598,16 +598,29 @@ static bool clip_to_limit(const SkRegion
   */
 static inline int round_down_to_int(SkScalar x) {
     double xx = x;
     xx += 0.5;
     double floorXX = floor(xx);
     return (int)floorXX - (xx == floorXX);
 }
 
+#ifdef SK_RASTERIZE_EVEN_ROUNDING
+/**
+  * Variant of SkDScalarRoundToInt that allows offseting the input by a small fraction
+  * while trying to preserve intermediate double-precision (rather than directly adding
+  * the bias to the input at lower single-precision).
+  */
+static inline int round_biased_to_int(SkScalar x, SkScalar bias) {
+    double xx = x;
+    xx += 0.5 + bias;
+    return (int)floor(xx);
+}
+#endif
+
 /**
   *  Variant of SkRect::round() that explicitly performs the rounding step (i.e. floor(x + 0.5))
   *  using double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(),
   *  which may be slower than calling SkScalarRountToInt(), but gives slightly more accurate
   *  results. Also rounds top and left using double, flooring when the fraction is exactly 0.5f.
   *
   *  e.g.
   *      SkScalar left = 0.5f;
@@ -615,21 +628,38 @@ static inline int round_down_to_int(SkSc
   *      SkASSERT(0 == ileft);  // <--- fails
   *      int ileft = round_down_to_int(left);
   *      SkASSERT(0 == ileft);  // <--- succeeds
   *      SkScalar right = 0.49999997f;
   *      int iright = SkScalarRoundToInt(right);
   *      SkASSERT(0 == iright);  // <--- fails
   *      iright = SkDScalarRoundToInt(right);
   *      SkASSERT(0 == iright);  // <--- succeeds
+  *
+  *
+  *  If using SK_RASTERIZE_EVEN_ROUNDING, we need to ensure that bottom and right account for
+  *  edges bounded by this rect being rounded to FDot6 format before being later rounded to an
+  *  integer. For example, a value like 0.499 can be below 0.5, but round to 0.5 as FDot6, which
+  *  would finally round to the integer 1, instead of just rounding to 0.
+  *
+  *  To handle this, a small bias of half an FDot6 increment is added before actually rounding to
+  *  an integer value. This simulates the rounding of SkScalarRoundToFDot6 without incurring the
+  *  range loss of converting to FDot6 format first, preserving the integer range for the SkIRect.
+  *  Thus, bottom and right are rounded in this manner (biased up), ensuring the rect is large enough.
+  *  Top and left can round as normal since they will round (biased down) to values less or equal
+  *  to the desired rect origin.
   */
 static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) {
     SkASSERT(dst);
     dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop),
+#ifdef SK_RASTERIZE_EVEN_ROUNDING
+             round_biased_to_int(src.fRight, 0.5f / SK_FDot6One), round_biased_to_int(src.fBottom, 0.5f / SK_FDot6One));
+#else
              SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom));
+#endif
 }
 
 void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
                       SkBlitter* blitter) {
     if (origClip.isEmpty()) {
         return;
     }
 
--- a/js/src/jit-test/tests/wasm/binary.js
+++ b/js/src/jit-test/tests/wasm/binary.js
@@ -198,16 +198,31 @@ function tableSection(initialSize) {
 function memorySection(initialSize) {
     var body = [];
     body.push(...varU32(1));           // number of memories
     body.push(...varU32(0x0));         // for now, no maximum
     body.push(...varU32(initialSize));
     return { name: memoryId, body };
 }
 
+function dataSection(segmentArrays) {
+    var body = [];
+    body.push(...varU32(segmentArrays.length));
+    for (let array of segmentArrays) {
+        body.push(...varU32(0)); // table index
+        body.push(...varU32(I32ConstCode));
+        body.push(...varS32(array.offset));
+        body.push(...varU32(EndCode));
+        body.push(...varU32(array.elems.length));
+        for (let elem of array.elems)
+            body.push(...varU32(elem));
+    }
+    return { name: dataId, body };
+}
+
 function elemSection(elemArrays) {
     var body = [];
     body.push(...varU32(elemArrays.length));
     for (let array of elemArrays) {
         body.push(...varU32(0)); // table index
         body.push(...varU32(I32ConstCode));
         body.push(...varS32(array.offset));
         body.push(...varU32(EndCode));
@@ -273,46 +288,70 @@ wasmEval(moduleWithSections([sigSection(
 
 wasmEval(moduleWithSections([
     sigSection([v2vSig]),
     importSection([{sigIndex:0, module:"a", func:""}]),
     declSection([0]),
     bodySection([v2vBody])
 ]), {a:{"":()=>{}}});
 
-assertErrorMessage(() => wasmEval(moduleWithSections([ {name: dataId, body: [], } ])), CompileError, /data section requires a memory section/);
+assertErrorMessage(() => wasmEval(moduleWithSections([ dataSection([{offset:1, elems:[]}]) ])), CompileError, /data segment requires a memory section/);
 
 wasmEval(moduleWithSections([tableSection(0)]));
 wasmEval(moduleWithSections([elemSection([])]));
 wasmEval(moduleWithSections([tableSection(0), elemSection([])]));
 wasmEval(moduleWithSections([tableSection(1), elemSection([{offset:1, elems:[]}])]));
 assertErrorMessage(() => wasmEval(moduleWithSections([tableSection(1), elemSection([{offset:0, elems:[0]}])])), CompileError, /table element out of range/);
 wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), tableSection(1), elemSection([{offset:0, elems:[0]}]), bodySection([v2vBody])]));
 wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), tableSection(2), elemSection([{offset:0, elems:[0,0]}]), bodySection([v2vBody])]));
 assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), tableSection(2), elemSection([{offset:0, elems:[0,1]}]), bodySection([v2vBody])])), CompileError, /table element out of range/);
 wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0,0,0]), tableSection(4), elemSection([{offset:0, elems:[0,1,0,2]}]), bodySection([v2vBody, v2vBody, v2vBody])]));
 wasmEval(moduleWithSections([sigSection([v2vSig,i2vSig]), declSection([0,0,1]), tableSection(3), elemSection([{offset:0,elems:[0,1,2]}]), bodySection([v2vBody, v2vBody, v2vBody])]));
 
-function invalidTableSection0() {
+function tableSection0() {
     var body = [];
     body.push(...varU32(0));           // number of tables
     return { name: tableId, body };
 }
 
-assertErrorMessage(() => wasmEval(moduleWithSections([invalidTableSection0()])), CompileError, /number of tables must be exactly one/);
+function invalidTableSection2() {
+    var body = [];
+    body.push(...varU32(2));           // number of tables
+    body.push(...varU32(AnyFuncCode));
+    body.push(...varU32(0x0));
+    body.push(...varU32(0));
+    body.push(...varU32(AnyFuncCode));
+    body.push(...varU32(0x0));
+    body.push(...varU32(0));
+    return { name: tableId, body };
+}
+
+wasmEval(moduleWithSections([tableSection0()]));
+assertErrorMessage(() => wasmEval(moduleWithSections([invalidTableSection2()])), CompileError, /number of tables must be at most one/);
 
 wasmEval(moduleWithSections([memorySection(0)]));
 
-function invalidMemorySection0() {
+function memorySection0() {
     var body = [];
     body.push(...varU32(0));           // number of memories
     return { name: memoryId, body };
 }
 
-assertErrorMessage(() => wasmEval(moduleWithSections([invalidMemorySection0()])), CompileError, /number of memories must be exactly one/);
+function invalidMemorySection2() {
+    var body = [];
+    body.push(...varU32(2));           // number of memories
+    body.push(...varU32(0x0));
+    body.push(...varU32(0));
+    body.push(...varU32(0x0));
+    body.push(...varU32(0));
+    return { name: memoryId, body };
+}
+
+wasmEval(moduleWithSections([memorySection0()]));
+assertErrorMessage(() => wasmEval(moduleWithSections([invalidMemorySection2()])), CompileError, /number of memories must be at most one/);
 
 // Test early 'end'
 const bodyMismatch = /function body length mismatch/;
 assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:[EndCode]})])])), CompileError, bodyMismatch);
 assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:[UnreachableCode,EndCode]})])])), CompileError, bodyMismatch);
 assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:[EndCode,UnreachableCode]})])])), CompileError, bodyMismatch);
 
 // Deep nesting shouldn't crash or even throw.
--- a/js/src/jit-test/tests/wasm/spec/call_indirect.wast
+++ b/js/src/jit-test/tests/wasm/spec/call_indirect.wast
@@ -355,8 +355,14 @@
 )
 (assert_invalid
   (module
     (table 0 anyfunc)
     (func $large-type (call_indirect 1012321300 (i32.const 0)))
   )
   "unknown type"
 )
+
+;; invalid table
+(assert_invalid 
+  (module (table anyfunc (elem 0 0)))
+  "unknown function 0"
+)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/custom_section.wast
@@ -0,0 +1,92 @@
+(module
+  "\00asm" "\0d\00\00\00"
+  "\00\24\10" "a custom section" "this is the payload"
+  "\00\20\10" "a custom section" "this is payload"
+  "\00\11\10" "a custom section" ""
+  "\00\10\00" "" "this is payload"
+  "\00\01\00" "" ""
+  "\00\24\10" "\00\00custom sectio\00" "this is the payload"
+)
+
+(module
+  "\00asm" "\0d\00\00\00"
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\01\01\00"  ;; type section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\02\01\00"  ;; import section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\03\01\00"  ;; function section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\04\01\00"  ;; table section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\05\01\00"  ;; memory section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\06\01\00"  ;; global section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\07\01\00"  ;; export section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\09\01\00"  ;; element section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\0a\01\00"  ;; code section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+  "\0b\01\00"  ;; data section
+  "\00\0e\06" "custom" "payload"
+  "\00\0e\06" "custom" "payload"
+)
+
+(module
+  "\00asm" "\0d\00\00\00"
+  "\01\07\01\60\02\7f\7f\01\7f"                ;; type section
+  "\00\1a\06" "custom" "this is the payload"   ;; custom section
+  "\03\02\01\00"                               ;; function section
+  "\07\0a\01\06\61\64\64\54\77\6f\00\00"       ;; export section
+  "\0a\09\01\07\00\20\00\20\01\6a\0b"          ;; code section
+  "\00\1b\07" "custom2" "this is the payload"  ;; custom section
+)
+
+(assert_malformed
+  (module
+    "\00asm" "\0d\00\00\00"
+    "\00\00"
+  )
+  "unexpected end"
+)
+
+(assert_malformed
+  (module
+    "\00asm" "\0d\00\00\00"
+    "\00\26\10" "a custom section" "this is the payload"
+  )
+  "unexpected end"
+)
+
+(assert_malformed
+  (module
+    "\00asm" "\0d\00\00\00"
+    "\00\25\10" "a custom section" "this is the payload"
+    "\00\24\10" "a custom section" "this is the payload"
+  )
+  "invalid section id"
+)
+
+(assert_malformed
+  (module
+    "\00asm" "\0d\00\00\00"
+    "\01\07\01\60\02\7f\7f\01\7f"                         ;; type section
+    "\00\25\10" "a custom section" "this is the payload"  ;; invalid length!
+    "\03\02\01\00"                                        ;; function section
+    "\0a\09\01\07\00\20\00\20\01\6a\0b"                   ;; code section
+    "\00\1b\07" "custom2" "this is the payload"           ;; custom section
+  )
+  "function and code section have inconsistent lengths"
+)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/spec/custom_section.wast.js
@@ -0,0 +1,1 @@
+var importedArgs = ['custom_section.wast']; load(scriptdir + '../wast.js');
--- a/js/src/jit-test/tests/wasm/spec/float_misc.wast
+++ b/js/src/jit-test/tests/wasm/spec/float_misc.wast
@@ -626,18 +626,8 @@
 (assert_return (invoke "f64.nearest" (f64.const -4.5)) (f64.const -4.0))
 (assert_return (invoke "f64.nearest" (f64.const -3.5)) (f64.const -4.0))
 
 ;; Test the maximum and minimum value for which nearest is not an identity operator.
 (assert_return (invoke "f32.nearest" (f32.const -0x1.fffffep+22)) (f32.const -0x1p+23))
 (assert_return (invoke "f32.nearest" (f32.const 0x1.fffffep+22)) (f32.const 0x1p+23))
 (assert_return (invoke "f64.nearest" (f64.const -0x1.fffffffffffffp+51)) (f64.const -0x1p+52))
 (assert_return (invoke "f64.nearest" (f64.const 0x1.fffffffffffffp+51)) (f64.const 0x1p+52))
-
-;; Test that min and max behave properly with signaling NaNs.
-(assert_return (invoke "f32.min" (f32.const 0.0) (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f32.min" (f32.const nan:0x200000) (f32.const 0.0)) (f32.const nan:0x600000))
-(assert_return (invoke "f32.max" (f32.const 0.0) (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f32.max" (f32.const nan:0x200000) (f32.const 0.0)) (f32.const nan:0x600000))
-(assert_return (invoke "f64.min" (f64.const 0.0) (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
-(assert_return (invoke "f64.min" (f64.const nan:0x4000000000000) (f64.const 0.0)) (f64.const nan:0xc000000000000))
-(assert_return (invoke "f64.max" (f64.const 0.0) (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
-(assert_return (invoke "f64.max" (f64.const nan:0x4000000000000) (f64.const 0.0)) (f64.const nan:0xc000000000000))
--- a/js/src/jit-test/tests/wasm/spec/globals.wast
+++ b/js/src/jit-test/tests/wasm/spec/globals.wast
@@ -90,8 +90,20 @@
   (module (global i32 (get_global 0)))
   "unknown global"
 )
 
 (assert_invalid
   (module (global i32 (get_global 1)) (global i32 (i32.const 0)))
   "unknown global"
 )
+
+(module
+  (import "spectest" "global" (global i32))
+)
+(assert_malformed (module "\00asm\0d\00\00\00\02\94\80\80\80\00\01\08\73\70\65\63\74\65\73\74\06\67\6c\6f\62\61\6c\03\7f\02") "invalid mutability")
+
+(module
+  (global i32 (i32.const 0))
+)
+(assert_malformed (module "\00asm\0d\00\00\00\06\86\80\80\80\00\01\7f\ff\41\00\0b") "invalid mutability")
+(assert_malformed (module "\00asm\0d\00\00\00\06\86\80\80\80\00\01\7f\d4\41\00\0b") "invalid mutability")
+(assert_malformed (module "\00asm\0d\00\00\00\06\86\80\80\80\00\01\7f\02\41\00\0b") "invalid mutability")
--- a/js/src/jit-test/tests/wasm/spec/memory.wast
+++ b/js/src/jit-test/tests/wasm/spec/memory.wast
@@ -12,28 +12,56 @@
   (data (i32.const 0) "a") (data (i32.const 1) "b") (data (i32.const 2) "c")
 )
 (module (global (import "spectest" "global") i32) (memory 1) (data (get_global 0) "a"))
 (module (global $g (import "spectest" "global") i32) (memory 1) (data (get_global $g) "a"))
 ;; Use of internal globals in constant expressions is not allowed in MVP.
 ;; (module (memory 1) (data (get_global 0) "a") (global i32 (i32.const 0)))
 ;; (module (memory 1) (data (get_global $g) "a") (global $g i32 (i32.const 0)))
 
+(assert_invalid (module (memory 0) (memory 0)) "multiple memories")
+(assert_invalid (module (memory (import "spectest" "memory") 0) (memory 0)) "multiple memories")
+
 (module (memory (data)) (func (export "memsize") (result i32) (current_memory)))
 (assert_return (invoke "memsize") (i32.const 0))
 (module (memory (data "")) (func (export "memsize") (result i32) (current_memory)))
 (assert_return (invoke "memsize") (i32.const 0))
 (module (memory (data "x")) (func (export "memsize") (result i32) (current_memory)))
 (assert_return (invoke "memsize") (i32.const 1))
 
 (assert_invalid (module (data (i32.const 0))) "unknown memory")
 (assert_invalid (module (data (i32.const 0) "")) "unknown memory")
 (assert_invalid (module (data (i32.const 0) "x")) "unknown memory")
 
 (assert_invalid
+  (module (func (drop (f32.load (i32.const 0)))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (f32.store (f32.const 0) (i32.const 0))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (drop (i32.load8_s (i32.const 0)))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (i32.store8 (i32.const 0) (i32.const 0))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (drop (current_memory))))
+  "unknown memory"
+)
+(assert_invalid
+  (module (func (drop (grow_memory (i32.const 0)))))
+  "unknown memory"
+)
+
+(assert_invalid
   (module (memory 1) (data (i64.const 0)))
   "type mismatch"
 )
 (assert_invalid
   (module (memory 1) (data (i32.ctz (i32.const 0))))
   "constant expression required"
 )
 (assert_invalid
--- a/js/src/jit-test/tests/wasm/spec/start.wast
+++ b/js/src/jit-test/tests/wasm/spec/start.wast
@@ -1,26 +1,28 @@
 (assert_invalid
   (module (func) (start 1))
   "unknown function"
 )
+
 (assert_invalid
   (module
     (func $main (result i32) (return (i32.const 0)))
     (start $main)
   )
   "start function"
 )
 (assert_invalid
   (module
     (func $main (param $a i32))
     (start $main)
   )
   "start function"
 )
+
 (module
   (memory (data "A"))
   (func $inc
     (i32.store8
       (i32.const 0)
       (i32.add
         (i32.load8_u (i32.const 0))
         (i32.const 1)
@@ -82,12 +84,17 @@
 )
 
 (module
   (func $print_i32 (import "spectest" "print") (param i32))
   (func $main (call $print_i32 (i32.const 2)))
   (start $main)
 )
 
+(module
+  (func $print (import "spectest" "print"))
+  (start $print)
+)
+
 (assert_trap
   (module (func $main (unreachable)) (start $main))
   "unreachable"
 )
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -172,17 +172,17 @@ SendCodeRangesToProfiler(CodeSegment& cs
         (void)start;
         (void)size;
 
 #ifdef JS_ION_PERF
         if (PerfFuncEnabled()) {
             const char* file = metadata.filename.get();
             unsigned line = codeRange.funcLineOrBytecode();
             unsigned column = 0;
-            writePerfSpewerAsmJSFunctionMap(start, size, file, line, column, name.begin());
+            writePerfSpewerWasmFunctionMap(start, size, file, line, column, name.begin());
         }
 #endif
 #ifdef MOZ_VTUNE
         if (IsVTuneProfilingActive()) {
             unsigned method_id = iJIT_GetNewMethodID();
             if (method_id == 0)
                 return;
             iJIT_Method_Load method;
--- a/js/src/wasm/WasmValidate.cpp
+++ b/js/src/wasm/WasmValidate.cpp
@@ -1084,21 +1084,23 @@ DecodeTableSection(Decoder& d, ModuleEnv
         return false;
     if (sectionStart == Decoder::NotStarted)
         return true;
 
     uint32_t numTables;
     if (!d.readVarU32(&numTables))
         return d.fail("failed to read number of tables");
 
-    if (numTables != 1)
-        return d.fail("the number of tables must be exactly one");
+    if (numTables > 1)
+        return d.fail("the number of tables must be at most one");
 
-    if (!DecodeTableLimits(d, &env->tables))
-        return false;
+    for (uint32_t i = 0; i < numTables; ++i) {
+        if (!DecodeTableLimits(d, &env->tables))
+            return false;
+    }
 
     if (!d.finishSection(sectionStart, sectionSize, "table"))
         return false;
 
     return true;
 }
 
 static bool
@@ -1109,21 +1111,23 @@ DecodeMemorySection(Decoder& d, ModuleEn
         return false;
     if (sectionStart == Decoder::NotStarted)
         return true;
 
     uint32_t numMemories;
     if (!d.readVarU32(&numMemories))
         return d.fail("failed to read number of memories");
 
-    if (numMemories != 1)
-        return d.fail("the number of memories must be exactly one");
+    if (numMemories > 1)
+        return d.fail("the number of memories must be at most one");
 
-    if (!DecodeMemoryLimits(d, env))
-        return false;
+    for (uint32_t i = 0; i < numMemories; ++i) {
+        if (!DecodeMemoryLimits(d, env))
+            return false;
+    }
 
     if (!d.finishSection(sectionStart, sectionSize, "memory"))
         return false;
 
     return true;
 }
 
 static bool
@@ -1529,34 +1533,34 @@ static bool
 DecodeDataSection(Decoder& d, ModuleEnvironment* env)
 {
     uint32_t sectionStart, sectionSize;
     if (!d.startSection(SectionId::Data, env, &sectionStart, &sectionSize, "data"))
         return false;
     if (sectionStart == Decoder::NotStarted)
         return true;
 
-    if (!env->usesMemory())
-        return d.fail("data section requires a memory section");
-
     uint32_t numSegments;
     if (!d.readVarU32(&numSegments))
         return d.fail("failed to read number of data segments");
 
     if (numSegments > MaxDataSegments)
         return d.fail("too many data segments");
 
     for (uint32_t i = 0; i < numSegments; i++) {
         uint32_t linearMemoryIndex;
         if (!d.readVarU32(&linearMemoryIndex))
             return d.fail("expected linear memory index");
 
         if (linearMemoryIndex != 0)
             return d.fail("linear memory index must currently be 0");
 
+        if (!env->usesMemory())
+            return d.fail("data segment requires a memory section");
+
         DataSegment seg;
         if (!DecodeInitializerExpression(d, env->globals, ValType::I32, &seg.offset))
             return false;
 
         if (!d.readVarU32(&seg.length))
             return d.fail("expected segment size");
 
         seg.bytecodeOffset = d.currentOffset();
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -8039,16 +8039,19 @@ PresShell::HandleEventInternal(WidgetEve
           mIsLastChromeOnlyEscapeKeyConsumed = false;
         } else {
           if (aEvent->mFlags.mOnlyChromeDispatch &&
               aEvent->mFlags.mDefaultPreventedByChrome) {
             mIsLastChromeOnlyEscapeKeyConsumed = true;
           }
         }
       }
+      if (aEvent->mMessage == eKeyDown) {
+        mIsLastKeyDownCanceled = aEvent->mFlags.mDefaultPrevented;
+      }
       break;
     }
     case eMouseUp:
       // reset the capturing content now that the mouse button is up
       SetCapturingContent(nullptr, 0);
       break;
     case eMouseMove:
       nsIPresShell::AllowMouseCapture(false);
@@ -8828,16 +8831,19 @@ PresShell::FireOrClearDelayedEvents(bool
   }
 
   if (mDocument) {
     nsCOMPtr<nsIDocument> doc = mDocument;
     while (!mIsDestroying && mDelayedEvents.Length() &&
            !doc->EventHandlingSuppressed()) {
       nsAutoPtr<DelayedEvent> ev(mDelayedEvents[0].forget());
       mDelayedEvents.RemoveElementAt(0);
+      if (ev->IsKeyPressEvent() && mIsLastKeyDownCanceled) {
+        continue;
+      }
       ev->Dispatch();
     }
     if (!doc->EventHandlingSuppressed()) {
       mDelayedEvents.Clear();
     }
   }
 }
 
@@ -9633,16 +9639,22 @@ PresShell::DelayedKeyEvent::DelayedKeyEv
                             aEvent->mMessage,
                             aEvent->mWidget);
   keyEvent->AssignKeyEventData(*aEvent, false);
   keyEvent->mFlags.mIsSynthesizedForTests = aEvent->mFlags.mIsSynthesizedForTests;
   keyEvent->mFlags.mIsSuppressedOrDelayed = true;
   mEvent = keyEvent;
 }
 
+bool
+PresShell::DelayedKeyEvent::IsKeyPressEvent()
+{
+  return mEvent->mMessage == eKeyPress;
+}
+
 // Start of DEBUG only code
 
 #ifdef DEBUG
 
 static void
 LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg)
 {
   nsAutoString n1, n2;
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -595,16 +595,17 @@ protected:
     return rv;
   }
 
   class DelayedEvent
   {
   public:
     virtual ~DelayedEvent() { }
     virtual void Dispatch() { }
+    virtual bool IsKeyPressEvent() { return false; }
   };
 
   class DelayedInputEvent : public DelayedEvent
   {
   public:
     virtual void Dispatch() override;
 
   protected:
@@ -619,16 +620,17 @@ protected:
   public:
     explicit DelayedMouseEvent(mozilla::WidgetMouseEvent* aEvent);
   };
 
   class DelayedKeyEvent : public DelayedInputEvent
   {
   public:
     explicit DelayedKeyEvent(mozilla::WidgetKeyboardEvent* aEvent);
+    virtual bool IsKeyPressEvent() override;
   };
 
   // Check if aEvent is a mouse event and record the mouse location for later
   // synth mouse moves.
   void RecordMouseLocation(mozilla::WidgetGUIEvent* aEvent);
   class nsSynthMouseMoveEvent final : public nsARefreshObserver {
   public:
     nsSynthMouseMoveEvent(PresShell* aPresShell, bool aFromScroll)
@@ -898,14 +900,16 @@ protected:
   bool                      mScaleToResolution : 1;
 
   // Whether the last chrome-only escape key event is consumed.
   bool                      mIsLastChromeOnlyEscapeKeyConsumed : 1;
 
   // Whether the widget has received a paint message yet.
   bool                      mHasReceivedPaintMessage : 1;
 
+  bool                      mIsLastKeyDownCanceled : 1;
+
   static bool               sDisableNonTestMouseEvents;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_PresShell_h
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/AnnexB.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2015, Mozilla Foundation and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "AnnexB.h"
-#include "BigEndian.h"
-
-#include <cstring>
-
-using mozilla::BigEndian;
-
-static const uint8_t kAnnexBDelimiter[] = { 0, 0, 0, 1 };
-
-/* static */ void
-AnnexB::ConvertFrameInPlace(std::vector<uint8_t>& aBuffer)
-{
-  for (size_t i = 0; i < aBuffer.size() - 4 - sizeof(kAnnexBDelimiter) + 1; ) {
-    uint32_t nalLen = BigEndian::readUint32(&aBuffer[i]);
-    memcpy(&aBuffer[i], kAnnexBDelimiter, sizeof(kAnnexBDelimiter));
-    i += nalLen + 4;
-  }
-}
-
-static void
-ConvertParamSetToAnnexB(std::vector<uint8_t>::const_iterator& aIter,
-                        size_t aCount,
-                        std::vector<uint8_t>& aOutAnnexB)
-{
-  for (size_t i = 0; i < aCount; i++) {
-    aOutAnnexB.insert(aOutAnnexB.end(), kAnnexBDelimiter,
-                      kAnnexBDelimiter + sizeof(kAnnexBDelimiter));
-
-    uint16_t len = BigEndian::readUint16(&*aIter); aIter += 2;
-    aOutAnnexB.insert(aOutAnnexB.end(), aIter, aIter + len); aIter += len;
-  }
-}
-
-/* static */ void
-AnnexB::ConvertConfig(const std::vector<uint8_t>& aBuffer,
-                      std::vector<uint8_t>& aOutAnnexB)
-{
-  // Skip past irrelevant headers
-  auto it = aBuffer.begin() + 5;
-
-  if (it >= aBuffer.end()) {
-    return;
-  }
-
-  size_t count = *(it++) & 31;
-
-  // Check that we have enough bytes for the Annex B conversion
-  // and the next size field. Bail if not.
-  if (it + count * 2 >= aBuffer.end()) {
-    return;
-  }
-
-  ConvertParamSetToAnnexB(it, count, aOutAnnexB);
-
-  // Check that we have enough bytes for the Annex B conversion.
-  count = *(it++);
-  if (it + count * 2 > aBuffer.end()) {
-    aOutAnnexB.clear();
-    return;
-  }
-
-  ConvertParamSetToAnnexB(it, count, aOutAnnexB);
-}
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/AnnexB.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2015, Mozilla Foundation and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __AnnexB_h__
-#define __AnnexB_h__
-
-#include <cstdint>
-#include <vector>
-
-class AnnexB
-{
-public:
-  static void ConvertFrameInPlace(std::vector<uint8_t>& aBuffer);
-
-  static void ConvertConfig(const std::vector<uint8_t>& aBuffer,
-                            std::vector<uint8_t>& aOutAnnexB);
-};
-
-#endif // __AnnexB_h__
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2015, Mozilla Foundation and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ClearKeyAsyncShutdown.h"
-#include "gmp-task-utils.h"
-
-ClearKeyAsyncShutdown::ClearKeyAsyncShutdown(GMPAsyncShutdownHost *aHostAPI)
-  : mHost(aHostAPI)
-{
-  CK_LOGD("ClearKeyAsyncShutdown::ClearKeyAsyncShutdown");
-  AddRef();
-}
-
-ClearKeyAsyncShutdown::~ClearKeyAsyncShutdown()
-{
-  CK_LOGD("ClearKeyAsyncShutdown::~ClearKeyAsyncShutdown");
-}
-
-void ShutdownTask(ClearKeyAsyncShutdown* aSelf, GMPAsyncShutdownHost* aHost)
-{
-  // Dumb implementation that just immediately reports completion.
-  // Real GMPs should ensure they are properly shutdown.
-  CK_LOGD("ClearKeyAsyncShutdown::BeginShutdown calling ShutdownComplete");
-  aHost->ShutdownComplete();
-  aSelf->Release();
-}
-
-void ClearKeyAsyncShutdown::BeginShutdown()
-{
-  CK_LOGD("ClearKeyAsyncShutdown::BeginShutdown dispatching asynchronous shutdown task");
-  GetPlatform()->runonmainthread(WrapTaskNM(ShutdownTask, this, mHost));
-}
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/ClearKeyAsyncShutdown.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2015, Mozilla Foundation and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __ClearKeyAsyncShutdown_h__
-#define __ClearKeyAsyncShutdown_h__
-
-#include "gmp-api/gmp-async-shutdown.h"
-#include "RefCounted.h"
-
-class ClearKeyAsyncShutdown : public GMPAsyncShutdown
-                            , public RefCounted
-{
-public:
-  explicit ClearKeyAsyncShutdown(GMPAsyncShutdownHost *aHostAPI);
-
-  void BeginShutdown() override;
-
-private:
-  virtual ~ClearKeyAsyncShutdown();
-
-  GMPAsyncShutdownHost* mHost;
-};
-
-#endif // __ClearKeyAsyncShutdown_h__
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/ClearKeyCDM.cpp
@@ -0,0 +1,195 @@
+#include "ClearKeyCDM.h"
+
+#include "ClearKeyUtils.h"
+
+using namespace cdm;
+
+ClearKeyCDM::ClearKeyCDM(Host_8* aHost)
+{
+  mHost = aHost;
+  mSessionManager = new ClearKeySessionManager(mHost);
+}
+
+void
+ClearKeyCDM::Initialize(bool aAllowDistinctiveIdentifier,
+                        bool aAllowPersistentState)
+{
+  mSessionManager->Init(aAllowDistinctiveIdentifier,
+                        aAllowPersistentState);
+
+#ifdef ENABLE_WMF
+  mVideoDecoder = new VideoDecoder(mHost);
+#endif
+}
+
+void
+ClearKeyCDM::SetServerCertificate(uint32_t aPromiseId,
+                                  const uint8_t* aServerCertificateData,
+                                  uint32_t aServerCertificateDataSize)
+{
+  mSessionManager->SetServerCertificate(aPromiseId,
+                                        aServerCertificateData,
+                                        aServerCertificateDataSize);
+}
+
+void
+ClearKeyCDM::CreateSessionAndGenerateRequest(uint32_t aPromiseId,
+                                             SessionType aSessionType,
+                                             InitDataType aInitDataType,
+                                             const uint8_t* aInitData,
+                                             uint32_t aInitDataSize)
+{
+  mSessionManager->CreateSession(aPromiseId,
+                                 aInitDataType,
+                                 aInitData,
+                                 aInitDataSize,
+                                 aSessionType);
+}
+
+void
+ClearKeyCDM::LoadSession(uint32_t aPromiseId,
+                         SessionType aSessionType,
+                         const char* aSessionId,
+                         uint32_t aSessionIdSize)
+{
+  mSessionManager->LoadSession(aPromiseId,
+                               aSessionId,
+                               aSessionIdSize);
+}
+
+void
+ClearKeyCDM::UpdateSession(uint32_t aPromiseId,
+                           const char* aSessionId,
+                           uint32_t aSessionIdSize,
+                           const uint8_t* aResponse,
+                           uint32_t aResponseSize)
+{
+  mSessionManager->UpdateSession(aPromiseId,
+                                 aSessionId,
+                                 aSessionIdSize,
+                                 aResponse,
+                                 aResponseSize);
+}
+
+void
+ClearKeyCDM::CloseSession(uint32_t aPromiseId,
+                          const char* aSessionId,
+                          uint32_t aSessionIdSize)
+{
+  mSessionManager->CloseSession(aPromiseId,
+                                aSessionId,
+                                aSessionIdSize);
+}
+
+void
+ClearKeyCDM::RemoveSession(uint32_t aPromiseId,
+                           const char* aSessionId,
+                           uint32_t aSessionIdSize)
+{
+  mSessionManager->RemoveSession(aPromiseId,
+                                 aSessionId,
+                                 aSessionIdSize);
+}
+
+void
+ClearKeyCDM::TimerExpired(void* aContext)
+{
+  // Clearkey is not interested in timers, so this method has not been
+  // implemented.
+  assert(false);
+}
+
+Status
+ClearKeyCDM::Decrypt(const InputBuffer& aEncryptedBuffer,
+                     DecryptedBlock* aDecryptedBuffer)
+{
+  return mSessionManager->Decrypt(aEncryptedBuffer, aDecryptedBuffer);
+}
+
+Status
+ClearKeyCDM::InitializeAudioDecoder(
+  const AudioDecoderConfig& aAudioDecoderConfig)
+{
+  // Audio decoding is not supported by Clearkey because Widevine doesn't
+  // support it and Clearkey's raison d'etre is to provide test coverage
+  // for paths that Widevine will exercise in the wild.
+  return Status::kDecodeError;
+}
+
+Status
+ClearKeyCDM::InitializeVideoDecoder(
+  const VideoDecoderConfig& aVideoDecoderConfig)
+{
+#ifdef ENABLE_WMF
+  return mVideoDecoder->InitDecode(aVideoDecoderConfig);
+#else
+  return Status::kDecodeError;
+#endif
+}
+
+void
+ClearKeyCDM::DeinitializeDecoder(StreamType aDecoderType)
+{
+#ifdef ENABLE_WMF
+  if (aDecoderType == StreamType::kStreamTypeVideo) {
+    mVideoDecoder->Reset();
+  }
+#endif
+}
+
+void
+ClearKeyCDM::ResetDecoder(StreamType aDecoderType)
+{
+#ifdef ENABLE_WMF
+  if (aDecoderType == StreamType::kStreamTypeVideo) {
+    mVideoDecoder->Reset();
+  }
+#endif
+}
+
+Status
+ClearKeyCDM::DecryptAndDecodeFrame(const InputBuffer& aEncryptedBuffer,
+                                   VideoFrame* aVideoFrame)
+{
+#ifdef ENABLE_WMF
+  return mVideoDecoder->Decode(aEncryptedBuffer, aVideoFrame);
+#else
+  return Status::kDecodeError;
+#endif
+}
+
+Status
+ClearKeyCDM::DecryptAndDecodeSamples(const InputBuffer& aEncryptedBuffer,
+                                     AudioFrames* aAudioFrame)
+{
+  // Audio decoding is not supported by Clearkey because Widevine doesn't
+  // support it and Clearkey's raison d'etre is to provide test coverage
+  // for paths that Widevine will exercise in the wild.
+  return Status::kDecodeError;
+}
+
+void
+ClearKeyCDM::OnPlatformChallengeResponse(
+  const PlatformChallengeResponse& aResponse)
+{
+  // This function should never be called and is not supported.
+  assert(false);
+}
+
+void
+ClearKeyCDM::OnQueryOutputProtectionStatus(QueryResult aResult,
+                                           uint32_t aLinkMask,
+                                           uint32_t aOutputProtectionMask)
+{
+  // This function should never be called and is not supported.
+  assert(false);
+}
+
+void
+ClearKeyCDM::Destroy()
+{
+  mSessionManager->DecryptingComplete();
+#ifdef ENABLE_WMF
+  mVideoDecoder->DecodingComplete();
+#endif
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/ClearKeyCDM.h
@@ -0,0 +1,98 @@
+#ifndef ClearKeyCDM_h_
+#define ClearKeyCDM_h_
+
+#include "ClearKeySessionManager.h"
+
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
+
+#ifdef ENABLE_WMF
+#include "WMFUtils.h"
+#include "VideoDecoder.h"
+#endif
+
+class ClearKeyCDM : public cdm::ContentDecryptionModule_8
+{
+private:
+  RefPtr<ClearKeySessionManager> mSessionManager;
+#ifdef ENABLE_WMF
+  RefPtr<VideoDecoder> mVideoDecoder;
+#endif
+
+protected:
+  cdm::Host_8* mHost;
+
+public:
+  explicit ClearKeyCDM(cdm::Host_8* mHost);
+
+  void Initialize(bool aAllowDistinctiveIdentifier,
+                  bool aAllowPersistentState) override;
+
+  void SetServerCertificate(uint32_t aPromiseId,
+                            const uint8_t* aServerCertificateData,
+                            uint32_t aServerCertificateDataSize)
+                            override;
+
+  void CreateSessionAndGenerateRequest(uint32_t aPromiseId,
+                                       cdm::SessionType aSessionType,
+                                       cdm::InitDataType aInitDataType,
+                                       const uint8_t* aInitData,
+                                       uint32_t aInitDataSize)
+                                       override;
+
+  void LoadSession(uint32_t aPromiseId,
+                   cdm::SessionType aSessionType,
+                   const char* aSessionId,
+                   uint32_t aSessionIdSize) override;
+
+  void UpdateSession(uint32_t aPromiseId,
+                     const char* aSessionId,
+                     uint32_t aSessionIdSize,
+                     const uint8_t* aResponse,
+                     uint32_t aResponseSize) override;
+
+  void CloseSession(uint32_t aPromiseId,
+                    const char* aSessionId,
+                    uint32_t aSessionIdSize) override;
+
+  void RemoveSession(uint32_t aPromiseId,
+                     const char* aSessionId,
+                     uint32_t aSessionIdSize) override;
+
+  void TimerExpired(void* aContext) override;
+
+  cdm::Status Decrypt(const cdm::InputBuffer& aEncryptedBuffer,
+                      cdm::DecryptedBlock* aDecryptedBuffer) override;
+
+  cdm::Status InitializeAudioDecoder(
+    const cdm::AudioDecoderConfig& aAudioDecoderConfig) override;
+
+  cdm::Status InitializeVideoDecoder(
+    const cdm::VideoDecoderConfig& aVideoDecoderConfig) override;
+
+  void DeinitializeDecoder(cdm::StreamType aDecoderType) override;
+
+  void ResetDecoder(cdm::StreamType aDecoderType) override;
+
+  cdm::Status DecryptAndDecodeFrame(
+    const cdm::InputBuffer& aEncryptedBuffer,
+    cdm::VideoFrame* aVideoFrame) override;
+
+  cdm::Status DecryptAndDecodeSamples(
+    const cdm::InputBuffer& aEncryptedBuffer,
+    cdm::AudioFrames* aAudioFrame) override;
+
+  void OnPlatformChallengeResponse(
+    const cdm::PlatformChallengeResponse& aResponse) override;
+
+  void
+    OnQueryOutputProtectionStatus(cdm::QueryResult aResult,
+                                  uint32_t aLinkMask,
+                                  uint32_t aOutputProtectionMask) override;
+
+  void Destroy() override;
+};
+
+#endif
\ No newline at end of file
--- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp
@@ -9,45 +9,48 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
+#include "ClearKeyDecryptionManager.h"
+
+#include "psshparser/PsshParser.h"
+
+#include <assert.h>
 #include <string.h>
 #include <vector>
 
-#include "ClearKeyDecryptionManager.h"
-#include "psshparser/PsshParser.h"
-#include "gmp-api/gmp-decryption.h"
-#include <assert.h>
+using namespace cdm;
 
 class ClearKeyDecryptor : public RefCounted
 {
 public:
   ClearKeyDecryptor();
 
   void InitKey(const Key& aKey);
   bool HasKey() const { return !!mKey.size(); }
 
-  GMPErr Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
+  Status Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
                  const CryptoMetaData& aMetadata);
 
   const Key& DecryptionKey() const { return mKey; }
 
 private:
   ~ClearKeyDecryptor();
 
   Key mKey;
 };
 
 
-/* static */ ClearKeyDecryptionManager* ClearKeyDecryptionManager::sInstance = nullptr;
+/* static */ ClearKeyDecryptionManager*
+ClearKeyDecryptionManager::sInstance = nullptr;
 
 /* static */ ClearKeyDecryptionManager*
 ClearKeyDecryptionManager::Get()
 {
   if (!sInstance) {
     sInstance = new ClearKeyDecryptionManager();
   }
   return sInstance;
@@ -68,24 +71,27 @@ ClearKeyDecryptionManager::~ClearKeyDecr
     it->second->Release();
   }
   mDecryptors.clear();
 }
 
 bool
 ClearKeyDecryptionManager::HasSeenKeyId(const KeyId& aKeyId) const
 {
-  CK_LOGD("ClearKeyDecryptionManager::SeenKeyId %s", mDecryptors.find(aKeyId) != mDecryptors.end() ? "t" : "f");
+  CK_LOGD("ClearKeyDecryptionManager::SeenKeyId %s",
+          mDecryptors.find(aKeyId) != mDecryptors.end() ? "t" : "f");
   return mDecryptors.find(aKeyId) != mDecryptors.end();
 }
 
 bool
 ClearKeyDecryptionManager::IsExpectingKeyForKeyId(const KeyId& aKeyId) const
 {
-  CK_LOGD("ClearKeyDecryptionManager::IsExpectingKeyForId %08x...", *(uint32_t*)&aKeyId[0]);
+  CK_LOGARRAY("ClearKeyDecryptionManager::IsExpectingKeyForId ",
+              aKeyId.data(),
+              aKeyId.size());
   const auto& decryptor = mDecryptors.find(aKeyId);
   return decryptor != mDecryptors.end() && !decryptor->second->HasKey();
 }
 
 bool
 ClearKeyDecryptionManager::HasKeyForKeyId(const KeyId& aKeyId) const
 {
   CK_LOGD("ClearKeyDecryptionManager::HasKeyForKeyId");
@@ -98,26 +104,33 @@ ClearKeyDecryptionManager::GetDecryption
 {
   assert(HasKeyForKeyId(aKeyId));
   return mDecryptors[aKeyId]->DecryptionKey();
 }
 
 void
 ClearKeyDecryptionManager::InitKey(KeyId aKeyId, Key aKey)
 {
-  CK_LOGD("ClearKeyDecryptionManager::InitKey %08x...", *(uint32_t*)&aKeyId[0]);
+  CK_LOGD("ClearKeyDecryptionManager::InitKey ",
+          aKeyId.data(),
+          aKeyId.size());
   if (IsExpectingKeyForKeyId(aKeyId)) {
+    CK_LOGARRAY("Initialized Key ", aKeyId.data(), aKeyId.size());
     mDecryptors[aKeyId]->InitKey(aKey);
+  } else {
+    CK_LOGARRAY("Failed to initialize key ", aKeyId.data(), aKeyId.size());
   }
 }
 
 void
 ClearKeyDecryptionManager::ExpectKeyId(KeyId aKeyId)
 {
-  CK_LOGD("ClearKeyDecryptionManager::ExpectKeyId %08x...", *(uint32_t*)&aKeyId[0]);
+  CK_LOGD("ClearKeyDecryptionManager::ExpectKeyId ",
+          aKeyId.data(),
+          aKeyId.size());
   if (!HasSeenKeyId(aKeyId)) {
     mDecryptors[aKeyId] = new ClearKeyDecryptor();
   }
   mDecryptors[aKeyId]->AddRef();
 }
 
 void
 ClearKeyDecryptionManager::ReleaseKeyId(KeyId aKeyId)
@@ -126,56 +139,66 @@ ClearKeyDecryptionManager::ReleaseKeyId(
   assert(HasSeenKeyId(aKeyId));
 
   ClearKeyDecryptor* decryptor = mDecryptors[aKeyId];
   if (!decryptor->Release()) {
     mDecryptors.erase(aKeyId);
   }
 }
 
-GMPErr
+Status
 ClearKeyDecryptionManager::Decrypt(std::vector<uint8_t>& aBuffer,
                                    const CryptoMetaData& aMetadata)
 {
   return Decrypt(&aBuffer[0], aBuffer.size(), aMetadata);
 }
 
-GMPErr
+Status
 ClearKeyDecryptionManager::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
                                    const CryptoMetaData& aMetadata)
 {
   CK_LOGD("ClearKeyDecryptionManager::Decrypt");
   if (!HasKeyForKeyId(aMetadata.mKeyId)) {
-    return GMPNoKeyErr;
+    CK_LOGARRAY("Unable to find decryptor for keyId: ",
+                aMetadata.mKeyId.data(),
+                aMetadata.mKeyId.size());
+    return Status::kNoKey;
   }
 
-  return mDecryptors[aMetadata.mKeyId]->Decrypt(aBuffer, aBufferSize, aMetadata);
+  CK_LOGARRAY("Found decryptor for keyId: ",
+              aMetadata.mKeyId.data(),
+              aMetadata.mKeyId.size());
+  return mDecryptors[aMetadata.mKeyId]->Decrypt(aBuffer,
+                                                aBufferSize,
+                                                aMetadata);
 }
 
 ClearKeyDecryptor::ClearKeyDecryptor()
 {
   CK_LOGD("ClearKeyDecryptor ctor");
 }
 
 ClearKeyDecryptor::~ClearKeyDecryptor()
 {
   if (HasKey()) {
-    CK_LOGD("ClearKeyDecryptor dtor; key = %08x...", *(uint32_t*)&mKey[0]);
+    CK_LOGARRAY("ClearKeyDecryptor dtor; key = ",
+                mKey.data(),
+                mKey.size());
   } else {
     CK_LOGD("ClearKeyDecryptor dtor");
   }
 }
 
 void
 ClearKeyDecryptor::InitKey(const Key& aKey)
 {
   mKey = aKey;
 }
 
-GMPErr
+Status
 ClearKeyDecryptor::Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
                            const CryptoMetaData& aMetadata)
 {
   CK_LOGD("ClearKeyDecryptor::Decrypt");
   // If the sample is split up into multiple encrypted subsamples, we need to
   // stitch them into one continuous buffer for decryption.
   std::vector<uint8_t> tmp(aBufferSize);
 
@@ -184,17 +207,17 @@ ClearKeyDecryptor::Decrypt(uint8_t* aBuf
     // continuous encrypted buffer.
     uint8_t* data = aBuffer;
     uint8_t* iter = &tmp[0];
     for (size_t i = 0; i < aMetadata.NumSubsamples(); i++) {
       data += aMetadata.mClearBytes[i];
       uint32_t cipherBytes = aMetadata.mCipherBytes[i];
       if (data + cipherBytes > aBuffer + aBufferSize) {
         // Trying to read past the end of the buffer!
-        return GMPCryptoErr;
+        return Status::kDecryptError;
       }
 
       memcpy(iter, data, cipherBytes);
 
       data += cipherBytes;
       iter += cipherBytes;
     }
 
@@ -222,10 +245,10 @@ ClearKeyDecryptor::Decrypt(uint8_t* aBuf
 
       data += cipherBytes;
       iter += cipherBytes;
     }
   } else {
     memcpy(aBuffer, &tmp[0], aBufferSize);
   }
 
-  return GMPNoErr;
+  return Status::kSuccess;
 }
--- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h
+++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.h
@@ -12,59 +12,70 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __ClearKeyDecryptionManager_h__
 #define __ClearKeyDecryptionManager_h__
 
-#include <map>
+#include "ClearKeyUtils.h"
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
+#include "RefCounted.h"
 
-#include "ClearKeyUtils.h"
-#include "RefCounted.h"
+#include <map>
 
 class ClearKeyDecryptor;
 
-class CryptoMetaData {
+class CryptoMetaData
+{
 public:
   CryptoMetaData() {}
 
-  explicit CryptoMetaData(const GMPEncryptedBufferMetadata* aCrypto)
+  explicit CryptoMetaData(const cdm::InputBuffer* aInputBuffer)
   {
-    Init(aCrypto);
+    Init(aInputBuffer);
   }
 
-  void Init(const GMPEncryptedBufferMetadata* aCrypto)
+  void Init(const cdm::InputBuffer* aInputBuffer)
   {
-    if (!aCrypto) {
+    if (!aInputBuffer) {
       assert(!IsValid());
       return;
     }
-    Assign(mKeyId, aCrypto->KeyId(), aCrypto->KeyIdSize());
-    Assign(mIV, aCrypto->IV(), aCrypto->IVSize());
-    Assign(mClearBytes, aCrypto->ClearBytes(), aCrypto->NumSubsamples());
-    Assign(mCipherBytes, aCrypto->CipherBytes(), aCrypto->NumSubsamples());
+
+    Assign(mKeyId, aInputBuffer->key_id, aInputBuffer->key_id_size);
+    Assign(mIV, aInputBuffer->iv, aInputBuffer->iv_size);
+
+    for (uint32_t i = 0; i < aInputBuffer->num_subsamples; ++i) {
+      const cdm::SubsampleEntry& subsample = aInputBuffer->subsamples[i];
+
+      mCipherBytes.push_back(subsample.cipher_bytes);
+      mClearBytes.push_back(subsample.clear_bytes);
+    }
   }
 
   bool IsValid() const {
     return !mKeyId.empty() &&
            !mIV.empty() &&
            !mCipherBytes.empty() &&
            !mClearBytes.empty();
   }
 
   size_t NumSubsamples() const {
     assert(mClearBytes.size() == mCipherBytes.size());
     return mClearBytes.size();
   }
 
   std::vector<uint8_t> mKeyId;
   std::vector<uint8_t> mIV;
-  std::vector<uint16_t> mClearBytes;
+  std::vector<uint32_t> mClearBytes;
   std::vector<uint32_t> mCipherBytes;
 };
 
 class ClearKeyDecryptionManager : public RefCounted
 {
 private:
   ClearKeyDecryptionManager();
   ~ClearKeyDecryptionManager();
@@ -80,22 +91,20 @@ public:
   const Key& GetDecryptionKey(const KeyId& aKeyId);
 
   // Create a decryptor for the given KeyId if one does not already exist.
   void InitKey(KeyId aKeyId, Key aKey);
   void ExpectKeyId(KeyId aKeyId);
   void ReleaseKeyId(KeyId aKeyId);
 
   // Decrypts buffer *in place*.
-  GMPErr Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
-                 const CryptoMetaData& aMetadata);
-  GMPErr Decrypt(std::vector<uint8_t>& aBuffer,
-                 const CryptoMetaData& aMetadata);
-
-  void Shutdown();
+  cdm::Status Decrypt(uint8_t* aBuffer, uint32_t aBufferSize,
+                      const CryptoMetaData& aMetadata);
+  cdm::Status Decrypt(std::vector<uint8_t>& aBuffer,
+                      const CryptoMetaData& aMetadata);
 
 private:
   bool IsExpectingKeyForKeyId(const KeyId& aKeyId) const;
 
   std::map<KeyId, ClearKeyDecryptor*> mDecryptors;
 };
 
 #endif // __ClearKeyDecryptionManager_h__
--- a/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyPersistence.cpp
@@ -10,251 +10,159 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "ClearKeyPersistence.h"
+
 #include "ClearKeyUtils.h"
 #include "ClearKeyStorage.h"
 #include "ClearKeySessionManager.h"
 #include "RefCounted.h"
 
+#include <assert.h>
 #include <stdint.h>
+#include <sstream>
 #include <string.h>
-#include <set>
-#include <vector>
-#include <sstream>
-#include <assert.h>
 
 using namespace std;
+using namespace cdm;
 
-// Whether we've loaded the persistent session ids from GMPStorage yet.
-enum PersistentKeyState {
-  UNINITIALIZED,
-  LOADING,
-  LOADED
-};
-static PersistentKeyState sPersistentKeyState = UNINITIALIZED;
+void
+ClearKeyPersistence::ReadAllRecordsFromIndex(function<void()>&& aOnComplete) {
+  // Clear what we think the index file contains, we're about to read it again.
+  mPersistentSessionIds.clear();
 
-// Set of session Ids of the persistent sessions created or residing in
-// storage.
-static set<uint32_t> sPersistentSessionIds;
-
-static vector<GMPTask*> sTasksBlockedOnSessionIdLoad;
+  // Hold a reference to the persistence manager, so it isn't released before
+  // we try and use it.
+  RefPtr<ClearKeyPersistence> self(this);
+  function<void(const uint8_t*, uint32_t)> onIndexSuccess =
+    [self, aOnComplete] (const uint8_t* data, uint32_t size)
+  {
+    CK_LOGD("ClearKeyPersistence: Loaded index file!");
+    const char* charData = (const char*)data;
 
-static void
-ReadAllRecordsFromIterator(GMPRecordIterator* aRecordIterator,
-                           void* aUserArg,
-                           GMPErr aStatus)
-{
-  assert(sPersistentKeyState == LOADING);
-  if (GMP_SUCCEEDED(aStatus)) {
-    // Extract the record names which are valid uint32_t's; they're
-    // the persistent session ids.
-    const char* name = nullptr;
-    uint32_t len = 0;
-    while (GMP_SUCCEEDED(aRecordIterator->GetName(&name, &len))) {
-      if (ClearKeyUtils::IsValidSessionId(name, len)) {
-        assert(name[len] == 0);
-        sPersistentSessionIds.insert(atoi(name));
+    stringstream ss(string(charData, charData + size));
+    string name;
+    while (getline(ss, name)) {
+      if (ClearKeyUtils::IsValidSessionId(name.data(), name.size())) {
+        self->mPersistentSessionIds.insert(atoi(name.c_str()));
       }
-      aRecordIterator->NextRecord();
     }
-  }
-  sPersistentKeyState = LOADED;
-  aRecordIterator->Close();
+
+    self->mPersistentKeyState = PersistentKeyState::LOADED;
+    aOnComplete();
+  };
 
-  for (size_t i = 0; i < sTasksBlockedOnSessionIdLoad.size(); i++) {
-    sTasksBlockedOnSessionIdLoad[i]->Run();
-    sTasksBlockedOnSessionIdLoad[i]->Destroy();
-  }
-  sTasksBlockedOnSessionIdLoad.clear();
+  function<void()> onIndexFailed =
+    [self, aOnComplete] ()
+  {
+    CK_LOGD("ClearKeyPersistence: Failed to load index file (it might not exist");
+    self->mPersistentKeyState = PersistentKeyState::LOADED;
+    aOnComplete();
+  };
+
+  string filename = "index";
+  ReadData(mHost, filename, move(onIndexSuccess), move(onIndexFailed));
 }
 
-/* static */ void
-ClearKeyPersistence::EnsureInitialized()
+void
+ClearKeyPersistence::WriteIndex() {
+  function <void()> onIndexSuccess =
+    [] ()
+  {
+    CK_LOGD("ClearKeyPersistence: Wrote index file");
+  };
+
+  function <void()> onIndexFail =
+    [] ()
+  {
+    CK_LOGD("ClearKeyPersistence: Failed to write index file (this is bad)");
+  };
+
+  stringstream ss;
+
+  for (const uint32_t& sessionId : mPersistentSessionIds) {
+    ss << sessionId;
+    ss << '\n';
+  }
+
+  string dataString = ss.str();
+  uint8_t* dataArray = (uint8_t*)dataString.data();
+  vector<uint8_t> data(dataArray, dataArray + dataString.size());
+
+  string filename = "index";
+  WriteData(mHost,
+            filename,
+            data,
+            move(onIndexSuccess),
+            move(onIndexFail));
+}
+
+
+ClearKeyPersistence::ClearKeyPersistence(Host_8* aHost)
 {
-  if (sPersistentKeyState == UNINITIALIZED) {
-    sPersistentKeyState = LOADING;
-    if (GMP_FAILED(EnumRecordNames(&ReadAllRecordsFromIterator))) {
-      sPersistentKeyState = LOADED;
-    }
+  this->mHost = aHost;
+}
+
+void
+ClearKeyPersistence::EnsureInitialized(bool aPersistentStateAllowed,
+                                       function<void()>&& aOnInitialized)
+{
+  if (aPersistentStateAllowed &&
+      mPersistentKeyState == PersistentKeyState::UNINITIALIZED) {
+    mPersistentKeyState = LOADING;
+    ReadAllRecordsFromIndex(move(aOnInitialized));
+  } else {
+    mPersistentKeyState = PersistentKeyState::LOADED;
+    aOnInitialized();
   }
 }
 
-/* static */ string
-ClearKeyPersistence::GetNewSessionId(GMPSessionType aSessionType)
+bool ClearKeyPersistence::IsLoaded() const
+{
+  return mPersistentKeyState == PersistentKeyState::LOADED;
+}
+
+string
+ClearKeyPersistence::GetNewSessionId(SessionType aSessionType)
 {
   static uint32_t sNextSessionId = 1;
 
   // Ensure we don't re-use a session id that was persisted.
-  while (Contains(sPersistentSessionIds, sNextSessionId)) {
+  while (Contains(mPersistentSessionIds, sNextSessionId)) {
     sNextSessionId++;
   }
 
   string sessionId;
   stringstream ss;
   ss << sNextSessionId;
   ss >> sessionId;
 
-  if (aSessionType == kGMPPersistentSession) {
-    sPersistentSessionIds.insert(sNextSessionId);
+  if (aSessionType == SessionType::kPersistentLicense) {
+    mPersistentSessionIds.insert(sNextSessionId);
+
+    // Save the updated index file.
+    WriteIndex();
   }
 
   sNextSessionId++;
 
   return sessionId;
 }
 
-
-class CreateSessionTask : public GMPTask {
-public:
-  CreateSessionTask(ClearKeySessionManager* aTarget,
-                    uint32_t aCreateSessionToken,
-                    uint32_t aPromiseId,
-                    const string& aInitDataType,
-                    const uint8_t* aInitData,
-                    uint32_t aInitDataSize,
-                    GMPSessionType aSessionType)
-    : mTarget(aTarget)
-    , mCreateSessionToken(aCreateSessionToken)
-    , mPromiseId(aPromiseId)
-    , mInitDataType(aInitDataType)
-    , mSessionType(aSessionType)
-  {
-    mInitData.insert(mInitData.end(),
-                     aInitData,
-                     aInitData + aInitDataSize);
-  }
-  virtual void Run() override {
-    mTarget->CreateSession(mCreateSessionToken,
-                           mPromiseId,
-                           mInitDataType.c_str(),
-                           mInitDataType.size(),
-                           &mInitData.front(),
-                           mInitData.size(),
-                           mSessionType);
-  }
-  virtual void Destroy() override {
-    delete this;
-  }
-private:
-  RefPtr<ClearKeySessionManager> mTarget;
-  uint32_t mCreateSessionToken;
-  uint32_t mPromiseId;
-  const string mInitDataType;
-  vector<uint8_t> mInitData;
-  GMPSessionType mSessionType;
-};
-
-
-/* static */ bool
-ClearKeyPersistence::DeferCreateSessionIfNotReady(ClearKeySessionManager* aInstance,
-                                                  uint32_t aCreateSessionToken,
-                                                  uint32_t aPromiseId,
-                                                  const string& aInitDataType,
-                                                  const uint8_t* aInitData,
-                                                  uint32_t aInitDataSize,
-                                                  GMPSessionType aSessionType)
+bool
+ClearKeyPersistence::IsPersistentSessionId(const string& aSessionId)
 {
-  if (sPersistentKeyState >= LOADED)  {
-    return false;
-  }
-  GMPTask* t = new CreateSessionTask(aInstance,
-                                     aCreateSessionToken,
-                                     aPromiseId,
-                                     aInitDataType,
-                                     aInitData,
-                                     aInitDataSize,
-                                     aSessionType);
-  sTasksBlockedOnSessionIdLoad.push_back(t);
-  return true;
+  return Contains(mPersistentSessionIds, atoi(aSessionId.c_str()));
 }
 
-class LoadSessionTask : public GMPTask {
-public:
-  LoadSessionTask(ClearKeySessionManager* aTarget,
-                  uint32_t aPromiseId,
-                  const char* aSessionId,
-                  uint32_t aSessionIdLength)
-    : mTarget(aTarget)
-    , mPromiseId(aPromiseId)
-    , mSessionId(aSessionId, aSessionId + aSessionIdLength)
-  {
-  }
-  virtual void Run() override {
-    mTarget->LoadSession(mPromiseId,
-                         mSessionId.c_str(),
-                         mSessionId.size());
-  }
-  virtual void Destroy() override {
-    delete this;
-  }
-private:
-  RefPtr<ClearKeySessionManager> mTarget;
-  uint32_t mPromiseId;
-  string mSessionId;
-};
-
-/* static */ bool
-ClearKeyPersistence::DeferLoadSessionIfNotReady(ClearKeySessionManager* aInstance,
-                                                uint32_t aPromiseId,
-                                                const char* aSessionId,
-                                                uint32_t aSessionIdLength)
+void
+ClearKeyPersistence::PersistentSessionRemoved(string& aSessionId)
 {
-  if (sPersistentKeyState >= LOADED)  {
-    return false;
-  }
-  GMPTask* t = new LoadSessionTask(aInstance,
-                                   aPromiseId,
-                                   aSessionId,
-                                   aSessionIdLength);
-  sTasksBlockedOnSessionIdLoad.push_back(t);
-  return true;
-}
+  mPersistentSessionIds.erase(atoi(aSessionId.c_str()));
 
-/* static */ bool
-ClearKeyPersistence::IsPersistentSessionId(const string& aSessionId)
-{
-  return Contains(sPersistentSessionIds, atoi(aSessionId.c_str()));
+  // Update the index file.
+  WriteIndex();
 }
-
-class LoadSessionFromKeysTask : public ReadContinuation {
-public:
-  LoadSessionFromKeysTask(ClearKeySessionManager* aTarget,
-                          const string& aSessionId,
-                          uint32_t aPromiseId)
-    : mTarget(aTarget)
-    , mSessionId(aSessionId)
-    , mPromiseId(aPromiseId)
-  {
-  }
-
-  virtual void ReadComplete(GMPErr aStatus,
-                            const uint8_t* aData,
-                            uint32_t aLength) override
-  {
-    mTarget->PersistentSessionDataLoaded(aStatus, mPromiseId, mSessionId, aData, aLength);
-  }
-private:
-  RefPtr<ClearKeySessionManager> mTarget;
-  string mSessionId;
-  uint32_t mPromiseId;
-};
-
-/* static */ void
-ClearKeyPersistence::LoadSessionData(ClearKeySessionManager* aInstance,
-                                     const string& aSid,
-                                     uint32_t aPromiseId)
-{
-  LoadSessionFromKeysTask* loadTask =
-    new LoadSessionFromKeysTask(aInstance, aSid, aPromiseId);
-  ReadData(aSid, loadTask);
-}
-
-/* static */ void
-ClearKeyPersistence::PersistentSessionRemoved(const string& aSessionId)
-{
-  sPersistentSessionIds.erase(atoi(aSessionId.c_str()));
-}
--- a/media/gmp-clearkey/0.1/ClearKeyPersistence.h
+++ b/media/gmp-clearkey/0.1/ClearKeyPersistence.h
@@ -12,42 +12,56 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __ClearKeyPersistence_h__
 #define __ClearKeyPersistence_h__
 
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
+#include "RefCounted.h"
+
+#include <functional>
+#include <set>
 #include <string>
-#include "gmp-api/gmp-decryption.h"
+#include <vector>
+
 
 class ClearKeySessionManager;
 
-class ClearKeyPersistence {
+// Whether we've loaded the persistent session ids yet.
+enum PersistentKeyState {
+  UNINITIALIZED,
+  LOADING,
+  LOADED
+};
+
+class ClearKeyPersistence : public RefCounted
+{
 public:
-  static void EnsureInitialized();
+  explicit ClearKeyPersistence(cdm::Host_8* aHost);
 
-  static std::string GetNewSessionId(GMPSessionType aSessionType);
+  void EnsureInitialized(bool aPersistentStateAllowed,
+                         std::function<void()>&& aOnInitialized);
 
-  static bool DeferCreateSessionIfNotReady(ClearKeySessionManager* aInstance,
-                                           uint32_t aCreateSessionToken,
-                                           uint32_t aPromiseId,
-                                           const std::string& aInitDataType,
-                                           const uint8_t* aInitData,
-                                           uint32_t aInitDataSize,
-                                           GMPSessionType aSessionType);
+  bool IsLoaded() const;
+
+  std::string GetNewSessionId(cdm::SessionType aSessionType);
+
+  bool IsPersistentSessionId(const std::string& aSid);
 
-  static bool DeferLoadSessionIfNotReady(ClearKeySessionManager* aInstance,
-                                         uint32_t aPromiseId,
-                                         const char* aSessionId,
-                                         uint32_t aSessionIdLength);
+  void PersistentSessionRemoved(std::string& aSid);
+private:
+  cdm::Host_8* mHost = nullptr;
 
-  static bool IsPersistentSessionId(const std::string& aSid);
+  PersistentKeyState mPersistentKeyState = PersistentKeyState::UNINITIALIZED;
 
-  static void LoadSessionData(ClearKeySessionManager* aInstance,
-                              const std::string& aSid,
-                              uint32_t aPromiseId);
+  std::set<uint32_t> mPersistentSessionIds;
 
-  static void PersistentSessionRemoved(const std::string& aSid);
+  void ReadAllRecordsFromIndex(std::function<void()>&& aOnComplete);
+  void WriteIndex();
 };
 
 #endif // __ClearKeyPersistence_h__
--- a/media/gmp-clearkey/0.1/ClearKeySession.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeySession.cpp
@@ -15,78 +15,64 @@
  */
 
 #include "BigEndian.h"
 #include "ClearKeyDecryptionManager.h"
 #include "ClearKeySession.h"
 #include "ClearKeyUtils.h"
 #include "ClearKeyStorage.h"
 #include "psshparser/PsshParser.h"
-#include "gmp-task-utils.h"
-#include "gmp-api/gmp-decryption.h"
+
 #include <assert.h>
 #include <string.h>
 
 using namespace mozilla;
+using namespace cdm;
+using namespace std;
 
 ClearKeySession::ClearKeySession(const std::string& aSessionId,
-                                 GMPDecryptorCallback* aCallback,
-                                 GMPSessionType aSessionType)
+                                 SessionType aSessionType)
   : mSessionId(aSessionId)
-  , mCallback(aCallback)
   , mSessionType(aSessionType)
 {
   CK_LOGD("ClearKeySession ctor %p", this);
 }
 
 ClearKeySession::~ClearKeySession()
 {
   CK_LOGD("ClearKeySession dtor %p", this);
-
-  std::vector<GMPMediaKeyInfo> key_infos;
-  for (const KeyId& keyId : mKeyIds) {
-    assert(ClearKeyDecryptionManager::Get()->HasSeenKeyId(keyId));
-    ClearKeyDecryptionManager::Get()->ReleaseKeyId(keyId);
-    key_infos.push_back(GMPMediaKeyInfo(&keyId[0], keyId.size(), kGMPUnknown));
-  }
-  mCallback->BatchedKeyStatusChanged(&mSessionId[0], mSessionId.size(),
-                                     key_infos.data(), key_infos.size());
 }
 
-void
-ClearKeySession::Init(uint32_t aCreateSessionToken,
-                      uint32_t aPromiseId,
-                      const std::string& aInitDataType,
-                      const uint8_t* aInitData, uint32_t aInitDataSize)
+bool
+ClearKeySession::Init(InitDataType aInitDataType,
+                      const uint8_t* aInitData,
+                      uint32_t aInitDataSize)
 {
   CK_LOGD("ClearKeySession::Init");
 
-  if (aInitDataType == "cenc") {
+  if (aInitDataType == InitDataType::kCenc) {
     ParseCENCInitData(aInitData, aInitDataSize, mKeyIds);
-  } else if (aInitDataType == "keyids") {
+  } else if (aInitDataType == InitDataType::kKeyIds) {
     ClearKeyUtils::ParseKeyIdsInitData(aInitData, aInitDataSize, mKeyIds);
-  } else if (aInitDataType == "webm" && aInitDataSize <= kMaxWebmInitDataSize) {
+  } else if (aInitDataType == InitDataType::kWebM &&
+             aInitDataSize <= kMaxWebmInitDataSize) {
     // "webm" initData format is simply the raw bytes of the keyId.
     vector<uint8_t> keyId;
     keyId.assign(aInitData, aInitData+aInitDataSize);
     mKeyIds.push_back(keyId);
   }
 
   if (!mKeyIds.size()) {
-    const char message[] = "Couldn't parse init data";
-    mCallback->RejectPromise(aPromiseId, kGMPTypeError, message, strlen(message));
-    return;
+    return false;
   }
 
-  mCallback->SetSessionId(aCreateSessionToken, &mSessionId[0], mSessionId.length());
-
-  mCallback->ResolvePromise(aPromiseId);
+  return true;
 }
 
-GMPSessionType
+SessionType
 ClearKeySession::Type() const
 {
   return mSessionType;
 }
 
 void
 ClearKeySession::AddKeyId(const KeyId& aKeyId)
 {
--- a/media/gmp-clearkey/0.1/ClearKeySession.h
+++ b/media/gmp-clearkey/0.1/ClearKeySession.h
@@ -13,46 +13,43 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __ClearKeySession_h__
 #define __ClearKeySession_h__
 
 #include "ClearKeyUtils.h"
-#include "gmp-api/gmp-decryption.h"
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
 
-class GMPBuffer;
-class GMPDecryptorCallback;
-class GMPDecryptorHost;
-class GMPEncryptedBufferMetadata;
+#include <string>
+#include <vector>
 
 class ClearKeySession
 {
 public:
   explicit ClearKeySession(const std::string& aSessionId,
-                           GMPDecryptorCallback* aCallback,
-                           GMPSessionType aSessionType);
+                           cdm::SessionType aSessionType);
 
   ~ClearKeySession();
 
   const std::vector<KeyId>& GetKeyIds() const { return mKeyIds; }
 
-  void Init(uint32_t aCreateSessionToken,
-            uint32_t aPromiseId,
-            const string& aInitDataType,
+  bool Init(cdm::InitDataType aInitDataType,
             const uint8_t* aInitData, uint32_t aInitDataSize);
 
-  GMPSessionType Type() const;
+  cdm::SessionType Type() const;
 
   void AddKeyId(const KeyId& aKeyId);
 
   const std::string& Id() const { return mSessionId; }
 
 private:
   const std::string mSessionId;
   std::vector<KeyId> mKeyIds;
 
-  GMPDecryptorCallback* mCallback;
-  const GMPSessionType mSessionType;
+  const cdm::SessionType mSessionType;
 };
 
 #endif // __ClearKeySession_h__
--- a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
@@ -9,98 +9,151 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
 #include "ClearKeyDecryptionManager.h"
 #include "ClearKeySessionManager.h"
 #include "ClearKeyUtils.h"
 #include "ClearKeyStorage.h"
 #include "ClearKeyPersistence.h"
-#include "gmp-task-utils.h"
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
+#include "psshparser/PsshParser.h"
+
 #include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
 
 using namespace std;
+using namespace cdm;
 
-ClearKeySessionManager::ClearKeySessionManager()
+ClearKeySessionManager::ClearKeySessionManager(Host_8* aHost)
   : mDecryptionManager(ClearKeyDecryptionManager::Get())
 {
   CK_LOGD("ClearKeySessionManager ctor %p", this);
   AddRef();
 
-  if (GetPlatform()->createthread(&mThread) != GMPNoErr) {
-    CK_LOGD("failed to create thread in clearkey cdm");
-    mThread = nullptr;
-  }
+  mHost = aHost;
+  mPersistence = new ClearKeyPersistence(mHost);
 }
 
 ClearKeySessionManager::~ClearKeySessionManager()
 {
   CK_LOGD("ClearKeySessionManager dtor %p", this);
 }
 
 void
-ClearKeySessionManager::Init(GMPDecryptorCallback* aCallback,
-                             bool aDistinctiveIdentifierAllowed,
+ClearKeySessionManager::Init(bool aDistinctiveIdentifierAllowed,
                              bool aPersistentStateAllowed)
 {
   CK_LOGD("ClearKeySessionManager::Init");
-  mCallback = aCallback;
-  ClearKeyPersistence::EnsureInitialized();
+
+  RefPtr<ClearKeySessionManager> self(this);
+  function<void()> onPersistentStateLoaded =
+    [self] ()
+  {
+    while (!self->mDeferredInitialize.empty()) {
+      function<void()> func = self->mDeferredInitialize.front();
+      self->mDeferredInitialize.pop();
+
+      func();
+    }
+  };
+
+  mPersistence->EnsureInitialized(aPersistentStateAllowed,
+                                  move(onPersistentStateLoaded));
 }
 
 void
-ClearKeySessionManager::CreateSession(uint32_t aCreateSessionToken,
-                                      uint32_t aPromiseId,
-                                      const char* aInitDataType,
-                                      uint32_t aInitDataTypeSize,
+ClearKeySessionManager::CreateSession(uint32_t aPromiseId,
+                                      InitDataType aInitDataType,
                                       const uint8_t* aInitData,
                                       uint32_t aInitDataSize,
-                                      GMPSessionType aSessionType)
+                                      SessionType aSessionType)
 {
-  CK_LOGD("ClearKeySessionManager::CreateSession type:%s", aInitDataType);
+  // Copy the init data so it is correctly captured by the lambda
+  vector<uint8_t> initData(aInitData, aInitData + aInitDataSize);
 
-  string initDataType(aInitDataType, aInitDataType + aInitDataTypeSize);
-  // initDataType must be "cenc", "keyids", or "webm".
-  if (initDataType != "cenc" &&
-      initDataType != "keyids" &&
-      initDataType != "webm") {
-    string message = "'" + initDataType + "' is an initDataType unsupported by ClearKey";
-    mCallback->RejectPromise(aPromiseId, kGMPNotSupportedError,
-                             message.c_str(), message.size());
+  RefPtr<ClearKeySessionManager> self(this);
+  function<void()> deferrer =
+    [self, aPromiseId, aInitDataType, initData, aSessionType] ()
+  {
+    self->CreateSession(aPromiseId,
+                        aInitDataType,
+                        initData.data(),
+                        initData.size(),
+                        aSessionType);
+  };
+
+  // If we haven't loaded, don't do this yet
+  if (MaybeDeferTillInitialized(deferrer)) {
     return;
   }
 
-  if (ClearKeyPersistence::DeferCreateSessionIfNotReady(this,
-                                                        aCreateSessionToken,
-                                                        aPromiseId,
-                                                        initDataType,
-                                                        aInitData,
-                                                        aInitDataSize,
-                                                        aSessionType)) {
+  CK_LOGD("ClearKeySessionManager::CreateSession type:%s", aInitDataType);
+
+  CK_LOGARRAY("ClearKeySessionManager::CreateSession initdata: ",
+              aInitData,
+              aInitDataSize);
+
+  // If 'DecryptingComplete' has been called mHost will be null so we can't
+  // won't be able to resolve our promise
+  if (!mHost) {
+    CK_LOGD("ClearKeySessionManager::CreateSession: mHost is nullptr")
     return;
   }
 
-  string sessionId = ClearKeyPersistence::GetNewSessionId(aSessionType);
+  // initDataType must be "cenc", "keyids", or "webm".
+  if (aInitDataType != InitDataType::kCenc &&
+      aInitDataType != InitDataType::kKeyIds &&
+      aInitDataType != InitDataType::kWebM) {
+
+    string message = "initDataType is not supported by ClearKey";
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kNotSupportedError,
+                           0,
+                           message.c_str(),
+                           message.size());
+
+    return;
+  }
+
+  string sessionId = mPersistence->GetNewSessionId(aSessionType);
   assert(mSessions.find(sessionId) == mSessions.end());
 
-  ClearKeySession* session = new ClearKeySession(sessionId, mCallback, aSessionType);
-  session->Init(aCreateSessionToken, aPromiseId, initDataType, aInitData, aInitDataSize);
+  ClearKeySession* session = new ClearKeySession(sessionId,
+                                                 aSessionType);
+
+  if (!session->Init(aInitDataType, aInitData, aInitDataSize)) {
+
+    CK_LOGD("Failed to initialize session: %s", sessionId.c_str());
+
+    const static char* message = "Failed to initialize session";
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kUnknownError,
+                           0,
+                           message,
+                           strlen(message));
+
+    return;
+  }
+
   mSessions[sessionId] = session;
 
   const vector<KeyId>& sessionKeys = session->GetKeyIds();
   vector<KeyId> neededKeys;
+
   for (auto it = sessionKeys.begin(); it != sessionKeys.end(); it++) {
     // Need to request this key ID from the client. We always send a key
     // request, whether or not another session has sent a request with the same
     // key ID. Otherwise a script can end up waiting for another script to
     // respond to the request (which may not necessarily happen).
     neededKeys.push_back(*it);
     mDecryptionManager->ExpectKeyId(*it);
   }
@@ -108,73 +161,120 @@ ClearKeySessionManager::CreateSession(ui
   if (neededKeys.empty()) {
     CK_LOGD("No keys needed from client.");
     return;
   }
 
   // Send a request for needed key data.
   string request;
   ClearKeyUtils::MakeKeyRequest(neededKeys, request, aSessionType);
-  mCallback->SessionMessage(&sessionId[0], sessionId.length(),
-                            kGMPLicenseRequest,
-                            (uint8_t*)&request[0], request.length());
+
+  // Resolve the promise with the new session information.
+  mHost->OnResolveNewSessionPromise(aPromiseId,
+                                    sessionId.c_str(),
+                                    sessionId.size());
+
+  mHost->OnSessionMessage(sessionId.c_str(),
+                          sessionId.size(),
+                          MessageType::kLicenseRequest,
+                          request.c_str(),
+                          request.size(),
+                          nullptr,
+                          0);
 }
 
 void
 ClearKeySessionManager::LoadSession(uint32_t aPromiseId,
                                     const char* aSessionId,
                                     uint32_t aSessionIdLength)
 {
-  CK_LOGD("ClearKeySessionManager::LoadSession");
+  // Copy the sessionId into a string so the lambda captures it properly.
+  string sessionId(aSessionId, aSessionId + aSessionIdLength);
 
-  if (!ClearKeyUtils::IsValidSessionId(aSessionId, aSessionIdLength)) {
-    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
+  // Hold a reference to the SessionManager so that it isn't released before
+  // we try to use it.
+  RefPtr<ClearKeySessionManager> self(this);
+  function<void()> deferrer =
+    [self, aPromiseId, sessionId] ()
+  {
+    self->LoadSession(aPromiseId, sessionId.data(), sessionId.size());
+  };
+
+  if (MaybeDeferTillInitialized(deferrer)) {
     return;
   }
 
-  if (ClearKeyPersistence::DeferLoadSessionIfNotReady(this,
-                                                      aPromiseId,
-                                                      aSessionId,
-                                                      aSessionIdLength)) {
+  CK_LOGD("ClearKeySessionManager::LoadSession");
+
+  // If the SessionManager has been shutdown mHost will be null and we won't
+  // be able to resolve the promise.
+  if (!mHost) {
     return;
   }
 
-  string sid(aSessionId, aSessionId + aSessionIdLength);
-  if (!ClearKeyPersistence::IsPersistentSessionId(sid)) {
-    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
+  if (!ClearKeyUtils::IsValidSessionId(aSessionId, aSessionIdLength)) {
+    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
+    return;
+  }
+
+  if (!mPersistence->IsPersistentSessionId(sessionId)) {
+    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
     return;
   }
 
-  // Callsback PersistentSessionDataLoaded with results...
-  ClearKeyPersistence::LoadSessionData(this, sid, aPromiseId);
+  function<void(const uint8_t*, uint32_t)> success =
+    [self, sessionId, aPromiseId] (const uint8_t* data, uint32_t size)
+  {
+    self->PersistentSessionDataLoaded(aPromiseId,
+                                      sessionId,
+                                      data,
+                                      size);
+  };
+
+  function<void()> failure = [self, sessionId, aPromiseId] {
+    if (!self->mHost) {
+      return;
+    }
+    // As per the API described in ContentDecryptionModule_8
+    self->mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
+  };
+
+  ReadData(mHost, sessionId, move(success), move(failure));
 }
 
 void
-ClearKeySessionManager::PersistentSessionDataLoaded(GMPErr aStatus,
-                                                    uint32_t aPromiseId,
+ClearKeySessionManager::PersistentSessionDataLoaded(uint32_t aPromiseId,
                                                     const string& aSessionId,
                                                     const uint8_t* aKeyData,
                                                     uint32_t aKeyDataSize)
 {
   CK_LOGD("ClearKeySessionManager::PersistentSessionDataLoaded");
-  if (GMP_FAILED(aStatus) ||
-      Contains(mSessions, aSessionId) ||
+
+  // Check that the SessionManager has not been shut down before we try and
+  // resolve any promises.
+  if (!mHost) {
+    return;
+  }
+
+  if (Contains(mSessions, aSessionId) ||
       (aKeyDataSize % (2 * CENC_KEY_LEN)) != 0) {
-    mCallback->ResolveLoadSessionPromise(aPromiseId, false);
+
+    // As per the instructions in ContentDecryptionModule_8
+    mHost->OnResolveNewSessionPromise(aPromiseId, nullptr, 0);
     return;
   }
 
   ClearKeySession* session = new ClearKeySession(aSessionId,
-                                                 mCallback,
-                                                 kGMPPersistentSession);
+                                                 SessionType::kPersistentLicense);
+
   mSessions[aSessionId] = session;
 
   uint32_t numKeys = aKeyDataSize / (2 * CENC_KEY_LEN);
 
-  vector<GMPMediaKeyInfo> key_infos;
+  vector<KeyInformation> keyInfos;
   vector<KeyIdPair> keyPairs;
   for (uint32_t i = 0; i < numKeys; i ++) {
     const uint8_t* base = aKeyData + 2 * CENC_KEY_LEN * i;
 
     KeyIdPair keyPair;
 
     keyPair.mKeyId = KeyId(base, base + CENC_KEY_LEN);
     assert(keyPair.mKeyId.size() == CENC_KEY_LEN);
@@ -182,91 +282,173 @@ ClearKeySessionManager::PersistentSessio
     keyPair.mKey = Key(base + CENC_KEY_LEN, base + 2 * CENC_KEY_LEN);
     assert(keyPair.mKey.size() == CENC_KEY_LEN);
 
     session->AddKeyId(keyPair.mKeyId);
 
     mDecryptionManager->ExpectKeyId(keyPair.mKeyId);
     mDecryptionManager->InitKey(keyPair.mKeyId, keyPair.mKey);
     mKeyIds.insert(keyPair.mKey);
+    keyPairs.push_back(keyPair);
 
-    keyPairs.push_back(keyPair);
-    key_infos.push_back(GMPMediaKeyInfo(&keyPairs[i].mKeyId[0],
-                                        keyPairs[i].mKeyId.size(),
-                                        kGMPUsable));
+    KeyInformation keyInfo = KeyInformation();
+    keyInfo.key_id = &keyPairs.back().mKeyId[0];
+    keyInfo.key_id_size = keyPair.mKeyId.size();
+    keyInfo.status = KeyStatus::kUsable;
+
+    keyInfos.push_back(keyInfo);
   }
-  mCallback->BatchedKeyStatusChanged(&aSessionId[0], aSessionId.size(),
-                                     key_infos.data(), key_infos.size());
 
-  mCallback->ResolveLoadSessionPromise(aPromiseId, true);
+  mHost->OnSessionKeysChange(&aSessionId[0],
+                             aSessionId.size(),
+                             true,
+                             keyInfos.data(),
+                             keyInfos.size());
+
+  mHost->OnResolveNewSessionPromise(aPromiseId,
+                                    aSessionId.c_str(),
+                                    aSessionId.size());
 }
 
 void
 ClearKeySessionManager::UpdateSession(uint32_t aPromiseId,
                                       const char* aSessionId,
                                       uint32_t aSessionIdLength,
                                       const uint8_t* aResponse,
                                       uint32_t aResponseSize)
 {
+  // Copy the method arguments so we can capture them in the lambda
+  string sessionId(aSessionId, aSessionId + aSessionIdLength);
+  vector<uint8_t> response(aResponse, aResponse + aResponseSize);
+
+  // Hold  a reference to the SessionManager so it isn't released before we
+  // callback.
+  RefPtr<ClearKeySessionManager> self(this);
+  function<void()> deferrer =
+    [self, aPromiseId, sessionId, response] ()
+  {
+    self->UpdateSession(aPromiseId,
+                        sessionId.data(),
+                        sessionId.size(),
+                        response.data(),
+                        response.size());
+  };
+
+  // If we haven't fully loaded, defer calling this method
+  if (MaybeDeferTillInitialized(deferrer)) {
+    return;
+  }
+
+  // Make sure the SessionManager has not been shutdown before we try and
+  // resolve any promises.
+  if (!mHost) {
+    return;
+  }
+
   CK_LOGD("ClearKeySessionManager::UpdateSession");
-  string sessionId(aSessionId, aSessionId + aSessionIdLength);
+  CK_LOGD("Updating session: %s", sessionId.c_str());
 
   auto itr = mSessions.find(sessionId);
   if (itr == mSessions.end() || !(itr->second)) {
     CK_LOGW("ClearKey CDM couldn't resolve session ID in UpdateSession.");
-    mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0);
+    CK_LOGD("Unable to find session: %s", sessionId.c_str());
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidAccessError,
+                           0,
+                           nullptr,
+                           0);
+
     return;
   }
   ClearKeySession* session = itr->second;
 
   // Verify the size of session response.
   if (aResponseSize >= kMaxSessionResponseLength) {
     CK_LOGW("Session response size is not within a reasonable size.");
-    mCallback->RejectPromise(aPromiseId, kGMPTypeError, nullptr, 0);
+    CK_LOGD("Failed to parse response for session %s", sessionId.c_str());
+
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidAccessError,
+                           0,
+                           nullptr,
+                           0);
+
     return;
   }
 
   // Parse the response for any (key ID, key) pairs.
   vector<KeyIdPair> keyPairs;
-  if (!ClearKeyUtils::ParseJWK(aResponse, aResponseSize, keyPairs, session->Type())) {
+  if (!ClearKeyUtils::ParseJWK(aResponse,
+                               aResponseSize,
+                               keyPairs,
+                               session->Type())) {
     CK_LOGW("ClearKey CDM failed to parse JSON Web Key.");
-    mCallback->RejectPromise(aPromiseId, kGMPTypeError, nullptr, 0);
+
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidAccessError,
+                           0,
+                           nullptr,
+                           0);
+
     return;
   }
 
-  vector<GMPMediaKeyInfo> key_infos;
+  vector<KeyInformation> keyInfos;
   for (size_t i = 0; i < keyPairs.size(); i++) {
     KeyIdPair& keyPair = keyPairs[i];
     mDecryptionManager->InitKey(keyPair.mKeyId, keyPair.mKey);
     mKeyIds.insert(keyPair.mKeyId);
-    key_infos.push_back(GMPMediaKeyInfo(&keyPair.mKeyId[0],
-                                        keyPair.mKeyId.size(),
-                                        kGMPUsable));
+
+    KeyInformation keyInfo = KeyInformation();
+    keyInfo.key_id = &keyPair.mKeyId[0];
+    keyInfo.key_id_size = keyPair.mKeyId.size();
+    keyInfo.status = KeyStatus::kUsable;
+
+    keyInfos.push_back(keyInfo);
   }
-  mCallback->BatchedKeyStatusChanged(aSessionId, aSessionIdLength,
-                                     key_infos.data(), key_infos.size());
 
-  if (session->Type() != kGMPPersistentSession) {
-    mCallback->ResolvePromise(aPromiseId);
+  mHost->OnSessionKeysChange(aSessionId,
+                             aSessionIdLength,
+                             true,
+                             keyInfos.data(),
+                             keyInfos.size());
+
+  if (session->Type() != SessionType::kPersistentLicense) {
+    mHost->OnResolvePromise(aPromiseId);
     return;
   }
 
   // Store the keys on disk. We store a record whose name is the sessionId,
   // and simply append each keyId followed by its key.
   vector<uint8_t> keydata;
   Serialize(session, keydata);
-  GMPTask* resolve = WrapTask(mCallback, &GMPDecryptorCallback::ResolvePromise, aPromiseId);
-  static const char* message = "Couldn't store cenc key init data";
-  GMPTask* reject = WrapTask(mCallback,
-                             &GMPDecryptorCallback::RejectPromise,
-                             aPromiseId,
-                             kGMPInvalidStateError,
-                             message,
-                             strlen(message));
-  StoreData(sessionId, keydata, resolve, reject);
+
+  function<void()> resolve = [self, aPromiseId] ()
+  {
+    if (!self->mHost) {
+      return;
+    }
+    self->mHost->OnResolvePromise(aPromiseId);
+  };
+
+  function<void()> reject = [self, aPromiseId] ()
+  {
+    if (!self->mHost) {
+      return;
+    }
+
+    static const char* message = "Couldn't store cenc key init data";
+    self->mHost->OnRejectPromise(aPromiseId,
+                                 Error::kInvalidStateError,
+                                 0,
+                                 message,
+                                 strlen(message));
+  };
+
+  WriteData(mHost, sessionId, keydata, move(resolve), move(reject));
 }
 
 void
 ClearKeySessionManager::Serialize(const ClearKeySession* aSession,
                                   std::vector<uint8_t>& aOutKeyData)
 {
   const std::vector<KeyId>& keyIds = aSession->GetKeyIds();
   for (size_t i = 0; i < keyIds.size(); i++) {
@@ -282,137 +464,205 @@ ClearKeySessionManager::Serialize(const 
   }
 }
 
 void
 ClearKeySessionManager::CloseSession(uint32_t aPromiseId,
                                      const char* aSessionId,
                                      uint32_t aSessionIdLength)
 {
+  // Copy the sessionId into a string so we capture it properly.
+  string sessionId(aSessionId, aSessionId + aSessionIdLength);
+  // Hold a reference to the session manager, so it doesn't get deleted
+  // before we need to use it.
+  RefPtr<ClearKeySessionManager> self(this);
+  function<void()> deferrer =
+    [self, aPromiseId, sessionId] ()
+  {
+    self->CloseSession(aPromiseId, sessionId.data(), sessionId.size());
+  };
+
+  // If we haven't loaded, call this method later.
+  if (MaybeDeferTillInitialized(deferrer)) {
+    return;
+  }
+
   CK_LOGD("ClearKeySessionManager::CloseSession");
 
-  string sessionId(aSessionId, aSessionId + aSessionIdLength);
+  // If DecryptingComplete has been called mHost will be null and we won't
+  // be able to resolve our promise.
+  if (!mHost) {
+    return;
+  }
+
   auto itr = mSessions.find(sessionId);
   if (itr == mSessions.end()) {
     CK_LOGW("ClearKey CDM couldn't close non-existent session.");
-    mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0);
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidAccessError,
+                           0,
+                           nullptr,
+                           0);
+
     return;
   }
 
   ClearKeySession* session = itr->second;
   assert(session);
 
   ClearInMemorySessionData(session);
-  mCallback->SessionClosed(aSessionId, aSessionIdLength);
-  mCallback->ResolvePromise(aPromiseId);
+
+  mHost->OnSessionClosed(aSessionId, aSessionIdLength);
+  mHost->OnResolvePromise(aPromiseId);
 }
 
 void
 ClearKeySessionManager::ClearInMemorySessionData(ClearKeySession* aSession)
 {
   mSessions.erase(aSession->Id());
   delete aSession;
 }
 
 void
 ClearKeySessionManager::RemoveSession(uint32_t aPromiseId,
                                       const char* aSessionId,
                                       uint32_t aSessionIdLength)
 {
+  // Copy the sessionId into a string so it can be captured for the lambda.
+  string sessionId(aSessionId, aSessionId + aSessionIdLength);
+
+  // Hold a reference to the SessionManager, so it isn't released before we
+  // try and use it.
+  RefPtr<ClearKeySessionManager> self(this);
+  function<void()> deferrer =
+    [self, aPromiseId, sessionId] ()
+  {
+    self->RemoveSession(aPromiseId, sessionId.data(), sessionId.size());
+  };
+
+  // If we haven't fully loaded, defer calling this method.
+  if (MaybeDeferTillInitialized(deferrer)) {
+    return;
+  }
+
+  // Check that the SessionManager has not been shutdown before we try and
+  // resolve any promises.
+  if (!mHost) {
+    return;
+  }
+
   CK_LOGD("ClearKeySessionManager::RemoveSession");
-  string sessionId(aSessionId, aSessionId + aSessionIdLength);
   auto itr = mSessions.find(sessionId);
   if (itr == mSessions.end()) {
     CK_LOGW("ClearKey CDM couldn't remove non-existent session.");
-    mCallback->RejectPromise(aPromiseId, kGMPNotFoundError, nullptr, 0);
+
+    mHost->OnRejectPromise(aPromiseId,
+                           Error::kInvalidAccessError,
+                           0,
+                           nullptr,
+                           0);
+
     return;
   }
 
   ClearKeySession* session = itr->second;
   assert(session);
   string sid = session->Id();
-  bool isPersistent = session->Type() == kGMPPersistentSession;
+  bool isPersistent = session->Type() == SessionType::kPersistentLicense;
   ClearInMemorySessionData(session);
 
   if (!isPersistent) {
-    mCallback->ResolvePromise(aPromiseId);
+    mHost->OnResolvePromise(aPromiseId);
     return;
   }
 
-  ClearKeyPersistence::PersistentSessionRemoved(sid);
+  mPersistence->PersistentSessionRemoved(sid);
 
-  // Overwrite the record storing the sessionId's key data with a zero
-  // length record to delete it.
   vector<uint8_t> emptyKeydata;
-  GMPTask* resolve = WrapTask(mCallback, &GMPDecryptorCallback::ResolvePromise, aPromiseId);
-  static const char* message = "Could not remove session";
-  GMPTask* reject = WrapTask(mCallback,
-                             &GMPDecryptorCallback::RejectPromise,
-                             aPromiseId,
-                             kGMPInvalidAccessError,
-                             message,
-                             strlen(message));
-  StoreData(sessionId, emptyKeydata, resolve, reject);
+
+  function<void()> resolve = [self, aPromiseId, sessionId] ()
+  {
+    if (!self->mHost) {
+      return;
+    }
+    self->mHost->OnResolvePromise(aPromiseId);
+  };
+
+  function<void()> reject = [self, aPromiseId, sessionId] ()
+  {
+    if (!self->mHost) {
+      return;
+    }
+    static const char* message = "Could not remove session";
+    self->mHost->OnRejectPromise(aPromiseId,
+                                 Error::kInvalidAccessError,
+                                 0,
+                                 message,
+                                 strlen(message));
+  };
+
+  WriteData(mHost, sessionId, emptyKeydata, move(resolve), move(reject));
 }
 
 void
 ClearKeySessionManager::SetServerCertificate(uint32_t aPromiseId,
                                              const uint8_t* aServerCert,
                                              uint32_t aServerCertSize)
 {
   // ClearKey CDM doesn't support this method by spec.
   CK_LOGD("ClearKeySessionManager::SetServerCertificate");
-  mCallback->RejectPromise(aPromiseId, kGMPNotSupportedError,
-                           nullptr /* message */, 0 /* messageLen */);
+  mHost->OnRejectPromise(aPromiseId,
+                         Error::kNotSupportedError,
+                         0,
+                         nullptr /* message */,
+                         0 /* messageLen */);
 }
 
-void
-ClearKeySessionManager::Decrypt(GMPBuffer* aBuffer,
-                                GMPEncryptedBufferMetadata* aMetadata)
+Status
+ClearKeySessionManager::Decrypt(const InputBuffer& aBuffer,
+                                DecryptedBlock* aDecryptedBlock)
 {
   CK_LOGD("ClearKeySessionManager::Decrypt");
 
-  if (!mThread) {
-    CK_LOGW("No decrypt thread");
-    mCallback->Decrypted(aBuffer, GMPGenericErr);
-    return;
-  }
+  CK_LOGARRAY("Key: ", aBuffer.key_id, aBuffer.key_id_size);
 
-  mThread->Post(WrapTaskRefCounted(this,
-                                   &ClearKeySessionManager::DoDecrypt,
-                                   aBuffer, aMetadata));
-}
+  Buffer* buffer = mHost->Allocate(aBuffer.data_size);
+  assert(buffer != nullptr);
+  assert(buffer->Data() != nullptr);
+  assert(buffer->Capacity() >= aBuffer.data_size);
+
+  memcpy(buffer->Data(), aBuffer.data, aBuffer.data_size);
 
-void
-ClearKeySessionManager::DoDecrypt(GMPBuffer* aBuffer,
-                                  GMPEncryptedBufferMetadata* aMetadata)
-{
-  CK_LOGD("ClearKeySessionManager::DoDecrypt");
+  Status status = mDecryptionManager->Decrypt(buffer->Data(),
+                                              buffer->Size(),
+                                              CryptoMetaData(&aBuffer));
 
-  GMPErr rv = mDecryptionManager->Decrypt(aBuffer->Data(), aBuffer->Size(),
-                                          CryptoMetaData(aMetadata));
-  CK_LOGD("DeDecrypt finished with code %x\n", rv);
-  mCallback->Decrypted(aBuffer, rv);
-}
+  aDecryptedBlock->SetDecryptedBuffer(buffer);
+  aDecryptedBlock->SetTimestamp(aBuffer.timestamp);
 
-void
-ClearKeySessionManager::Shutdown()
-{
-  CK_LOGD("ClearKeySessionManager::Shutdown %p", this);
-
-  for (auto it = mSessions.begin(); it != mSessions.end(); it++) {
-    delete it->second;
-  }
-  mSessions.clear();
+  return status;
 }
 
 void
 ClearKeySessionManager::DecryptingComplete()
 {
   CK_LOGD("ClearKeySessionManager::DecryptingComplete %p", this);
 
-  GMPThread* thread = mThread;
-  thread->Join();
+  for (auto it = mSessions.begin(); it != mSessions.end(); it++) {
+    delete it->second;
+  }
+  mSessions.clear();
 
-  Shutdown();
   mDecryptionManager = nullptr;
+  mHost = nullptr;
+
   Release();
 }
+
+bool ClearKeySessionManager::MaybeDeferTillInitialized(function<void()> aMaybeDefer)
+{
+  if (mPersistence->IsLoaded()) {
+    return false;
+  }
+
+  mDeferredInitialize.emplace(move(aMaybeDefer));
+  return true;
+}
--- a/media/gmp-clearkey/0.1/ClearKeySessionManager.h
+++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.h
@@ -1,100 +1,102 @@
 /*
- * Copyright 2015, Mozilla Foundation and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+* Copyright 2015, Mozilla Foundation and contributors
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
 
 #ifndef __ClearKeyDecryptor_h__
 #define __ClearKeyDecryptor_h__
 
+#include "ClearKeyDecryptionManager.h"
+#include "ClearKeyPersistence.h"
+#include "ClearKeySession.h"
+#include "ClearKeyUtils.h"
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
+#include "RefCounted.h"
+
+#include <functional>
 #include <map>
+#include <queue>
 #include <set>
 #include <string>
-#include <vector>
 
-#include "ClearKeyDecryptionManager.h"
-#include "ClearKeySession.h"
-#include "ClearKeyUtils.h"
-#include "gmp-api/gmp-decryption.h"
-#include "RefCounted.h"
-
-class ClearKeySessionManager final : public GMPDecryptor
-                                   , public RefCounted
+class ClearKeySessionManager final : public RefCounted
 {
 public:
-  ClearKeySessionManager();
+  explicit ClearKeySessionManager(cdm::Host_8* aHost);
 
-  virtual void Init(GMPDecryptorCallback* aCallback,
-                    bool aDistinctiveIdentifierAllowed,
-                    bool aPersistentStateAllowed) override;
+  void Init(bool aDistinctiveIdentifierAllowed,
+            bool aPersistentStateAllowed);
 
-  virtual void CreateSession(uint32_t aCreateSessionToken,
-                             uint32_t aPromiseId,
-                             const char* aInitDataType,
-                             uint32_t aInitDataTypeSize,
-                             const uint8_t* aInitData,
-                             uint32_t aInitDataSize,
-                             GMPSessionType aSessionType) override;
+  void CreateSession(uint32_t aPromiseId,
+                     cdm::InitDataType aInitDataType,
+                     const uint8_t* aInitData,
+                     uint32_t aInitDataSize,
+                     cdm::SessionType aSessionType);
 
-  virtual void LoadSession(uint32_t aPromiseId,
-                           const char* aSessionId,
-                           uint32_t aSessionIdLength) override;
+  void LoadSession(uint32_t aPromiseId,
+                   const char* aSessionId,
+                   uint32_t aSessionIdLength);
 
-  virtual void UpdateSession(uint32_t aPromiseId,
-                             const char* aSessionId,
-                             uint32_t aSessionIdLength,
-                             const uint8_t* aResponse,
-                             uint32_t aResponseSize) override;
+  void UpdateSession(uint32_t aPromiseId,
+                     const char* aSessionId,
+                     uint32_t aSessionIdLength,
+                     const uint8_t* aResponse,
+                     uint32_t aResponseSize);
 
-  virtual void CloseSession(uint32_t aPromiseId,
-                            const char* aSessionId,
-                            uint32_t aSessionIdLength) override;
+  void CloseSession(uint32_t aPromiseId,
+                    const char* aSessionId,
+                    uint32_t aSessionIdLength);
 
-  virtual void RemoveSession(uint32_t aPromiseId,
-                             const char* aSessionId,
-                             uint32_t aSessionIdLength) override;
+  void RemoveSession(uint32_t aPromiseId,
+                     const char* aSessionId,
+                     uint32_t aSessionIdLength);
 
-  virtual void SetServerCertificate(uint32_t aPromiseId,
-                                    const uint8_t* aServerCert,
-                                    uint32_t aServerCertSize) override;
+  void SetServerCertificate(uint32_t aPromiseId,
+                            const uint8_t* aServerCert,
+                            uint32_t aServerCertSize);
 
-  virtual void Decrypt(GMPBuffer* aBuffer,
-                       GMPEncryptedBufferMetadata* aMetadata) override;
+  cdm::Status
+  Decrypt(const cdm::InputBuffer& aBuffer,
+          cdm::DecryptedBlock* aDecryptedBlock);
 
-  virtual void DecryptingComplete() override;
+  void DecryptingComplete();
 
-  void PersistentSessionDataLoaded(GMPErr aStatus,
-                                   uint32_t aPromiseId,
+  void PersistentSessionDataLoaded(uint32_t aPromiseId,
                                    const std::string& aSessionId,
                                    const uint8_t* aKeyData,
                                    uint32_t aKeyDataSize);
 
 private:
   ~ClearKeySessionManager();
 
-  void DoDecrypt(GMPBuffer* aBuffer, GMPEncryptedBufferMetadata* aMetadata);
-  void Shutdown();
-
   void ClearInMemorySessionData(ClearKeySession* aSession);
-  void Serialize(const ClearKeySession* aSession, std::vector<uint8_t>& aOutKeyData);
+  bool MaybeDeferTillInitialized(std::function<void()> aMaybeDefer);
+  void Serialize(const ClearKeySession* aSession,
+                 std::vector<uint8_t>& aOutKeyData);
 
   RefPtr<ClearKeyDecryptionManager> mDecryptionManager;
+  RefPtr<ClearKeyPersistence> mPersistence;
 
-  GMPDecryptorCallback* mCallback;
-  GMPThread* mThread;
+  cdm::Host_8* mHost = nullptr;
 
   std::set<KeyId> mKeyIds;
   std::map<std::string, ClearKeySession*> mSessions;
+
+  std::queue<std::function<void()>> mDeferredInitialize;
 };
 
 #endif // __ClearKeyDecryptor_h__
--- a/media/gmp-clearkey/0.1/ClearKeyStorage.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyStorage.cpp
@@ -10,185 +10,217 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "ClearKeyStorage.h"
+
 #include "ClearKeyUtils.h"
 
-#include "gmp-task-utils.h"
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
 
 #include <assert.h>
 #include "ArrayUtils.h"
-
 #include <vector>
 
-static GMPErr
-RunOnMainThread(GMPTask* aTask)
-{
-  return GetPlatform()->runonmainthread(aTask);
-}
+using namespace cdm;
+using namespace std;
 
-GMPErr
-OpenRecord(const char* aName,
-           uint32_t aNameLength,
-           GMPRecord** aOutRecord,
-           GMPRecordClient* aClient)
+class WriteRecordClient : public FileIOClient
 {
-  return GetPlatform()->createrecord(aName, aNameLength, aOutRecord, aClient);
-}
-
-class WriteRecordClient : public GMPRecordClient {
 public:
   /*
    * This function will take the memory ownership of the parameters and
    * delete them when done.
    */
-  static void Write(const std::string& aRecordName,
-                    const std::vector<uint8_t>& aData,
-                    GMPTask* aOnSuccess,
-                    GMPTask* aOnFailure) {
-    (new WriteRecordClient(aData, aOnSuccess, aOnFailure))->Do(aRecordName);
+  static void Write(Host_8* aHost,
+                    string& aRecordName,
+                    const vector<uint8_t>& aData,
+                    function<void()>&& aOnSuccess,
+                    function<void()>&& aOnFailure)
+{
+    WriteRecordClient* client = new WriteRecordClient(aData,
+                                                      move(aOnSuccess),
+                                                      move(aOnFailure));
+    client->Do(aRecordName, aHost);
   }
 
-  virtual void OpenComplete(GMPErr aStatus) override {
-    if (GMP_FAILED(aStatus) ||
-        GMP_FAILED(mRecord->Write(&mData.front(), mData.size()))) {
-      Done(mOnFailure, mOnSuccess);
+  void OnOpenComplete(Status aStatus) override
+  {
+    // If we hit an error, fail.
+    if (aStatus != Status::kSuccess) {
+      Done(aStatus);
+    } else if (mFileIO) { // Otherwise, write our data to the file.
+      mFileIO->Write(&mData[0], mData.size());
     }
   }
 
-  virtual void ReadComplete(GMPErr aStatus,
-                            const uint8_t* aData,
-                            uint32_t aDataSize) override {
-    assert(false); // Should not reach here.
+  void OnReadComplete(Status aStatus,
+                      const uint8_t* aData,
+                      uint32_t aDataSize) override
+  {
+    // This function should never be called, we only ever write data with this
+    // client.
+    assert(false);
   }
 
-  virtual void WriteComplete(GMPErr aStatus) override {
-    if (GMP_FAILED(aStatus)) {
-      Done(mOnFailure, mOnSuccess);
-    } else {
-      Done(mOnSuccess, mOnFailure);
-    }
+  void OnWriteComplete(Status aStatus) override
+  {
+    Done(aStatus);
   }
 
 private:
-  WriteRecordClient(const std::vector<uint8_t>& aData,
-                    GMPTask* aOnSuccess,
-                    GMPTask* aOnFailure)
-    : mRecord(nullptr)
-    , mOnSuccess(aOnSuccess)
-    , mOnFailure(aOnFailure)
+  explicit WriteRecordClient(const vector<uint8_t>& aData,
+                             function<void()>&& aOnSuccess,
+                             function<void()>&& aOnFailure)
+    : mFileIO(nullptr)
+    , mOnSuccess(move(aOnSuccess))
+    , mOnFailure(move(aOnFailure))
     , mData(aData) {}
 
-  void Do(const std::string& aName) {
-    auto err = OpenRecord(aName.c_str(), aName.size(), &mRecord, this);
-    if (GMP_FAILED(err) ||
-        GMP_FAILED(mRecord->Open())) {
-      Done(mOnFailure, mOnSuccess);
-    }
+  void Do(const string& aName, Host_8* aHost)
+  {
+    // Initialize the FileIO.
+    mFileIO = aHost->CreateFileIO(this);
+    mFileIO->Open(aName.c_str(), aName.size());
   }
 
-  void Done(GMPTask* aToRun, GMPTask* aToDestroy) {
+  void Done(cdm::FileIOClient::Status aStatus)
+  {
     // Note: Call Close() before running continuation, in case the
     // continuation tries to open the same record; if we call Close()
     // after running the continuation, the Close() call will arrive
     // just after the Open() call succeeds, immediately closing the
     // record we just opened.
-    if (mRecord) {
-      mRecord->Close();
+    if (mFileIO) {
+      mFileIO->Close();
     }
-    aToDestroy->Destroy();
-    RunOnMainThread(aToRun);
+
+    if (IO_SUCCEEDED(aStatus)) {
+      mOnSuccess();
+    } else {
+      mOnFailure();
+    }
+
     delete this;
   }
 
-  GMPRecord* mRecord;
-  GMPTask* mOnSuccess;
-  GMPTask* mOnFailure;
-  const std::vector<uint8_t> mData;
+  FileIO* mFileIO = nullptr;
+
+  function<void()> mOnSuccess;
+  function<void()> mOnFailure;
+
+  const vector<uint8_t> mData;
 };
 
 void
-StoreData(const std::string& aRecordName,
-          const std::vector<uint8_t>& aData,
-          GMPTask* aOnSuccess,
-          GMPTask* aOnFailure)
+WriteData(Host_8* aHost,
+          string& aRecordName,
+          const vector<uint8_t>& aData,
+          function<void()>&& aOnSuccess,
+          function<void()>&& aOnFailure)
 {
-  WriteRecordClient::Write(aRecordName, aData, aOnSuccess, aOnFailure);
+  WriteRecordClient::Write(aHost,
+                           aRecordName,
+                           aData,
+                           move(aOnSuccess),
+                           move(aOnFailure));
 }
 
-class ReadRecordClient : public GMPRecordClient {
+class ReadRecordClient : public FileIOClient
+{
 public:
   /*
    * This function will take the memory ownership of the parameters and
    * delete them when done.
    */
-  static void Read(const std::string& aRecordName,
-                   ReadContinuation* aContinuation) {
-    assert(aContinuation);
-    (new ReadRecordClient(aContinuation))->Do(aRecordName);
+  static void Read(Host_8* aHost,
+                   string& aRecordName,
+                   function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
+                   function<void()>&& aOnFailure)
+  {
+
+    (new ReadRecordClient(move(aOnSuccess), move(aOnFailure)))->
+      Do(aRecordName, aHost);
   }
 
-  virtual void OpenComplete(GMPErr aStatus) override {
+  void OnOpenComplete(Status aStatus) override
+  {
     auto err = aStatus;
-    if (GMP_FAILED(err) ||
-        GMP_FAILED(err = mRecord->Read())) {
+    if (aStatus != Status::kSuccess) {
       Done(err, nullptr, 0);
+    } else {
+      mFileIO->Read();
     }
   }
 
-  virtual void ReadComplete(GMPErr aStatus,
-                            const uint8_t* aData,
-                            uint32_t aDataSize) override {
+  void OnReadComplete(Status aStatus,
+                      const uint8_t* aData,
+                      uint32_t aDataSize) override
+  {
     Done(aStatus, aData, aDataSize);
   }
 
-  virtual void WriteComplete(GMPErr aStatus) override {
-    assert(false); // Should not reach here.
+  void OnWriteComplete(Status aStatus) override
+  {
+    // We should never reach here, this client only ever reads data.
+    assert(false);
   }
 
 private:
-  explicit ReadRecordClient(ReadContinuation* aContinuation)
-    : mRecord(nullptr)
-    , mContinuation(aContinuation) {}
+  explicit ReadRecordClient(function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
+                            function<void()>&& aOnFailure)
+    : mFileIO(nullptr)
+    , mOnSuccess(move(aOnSuccess))
+    , mOnFailure(move(aOnFailure))
+  {}
 
-  void Do(const std::string& aName) {
-    auto err = OpenRecord(aName.c_str(), aName.size(), &mRecord, this);
-    if (GMP_FAILED(err) ||
-        GMP_FAILED(err = mRecord->Open())) {
-      Done(err, nullptr, 0);
-    }
+  void Do(const string& aName, Host_8* aHost)
+  {
+    mFileIO = aHost->CreateFileIO(this);
+    mFileIO->Open(aName.c_str(), aName.size());
   }
 
-  void Done(GMPErr err, const uint8_t* aData, uint32_t aDataSize) {
+  void Done(cdm::FileIOClient::Status aStatus,
+            const uint8_t* aData,
+            uint32_t aDataSize)
+  {
     // Note: Call Close() before running continuation, in case the
     // continuation tries to open the same record; if we call Close()
     // after running the continuation, the Close() call will arrive
     // just after the Open() call succeeds, immediately closing the
     // record we just opened.
-    if (mRecord) {
-      mRecord->Close();
+    if (mFileIO) {
+      mFileIO->Close();
     }
-    mContinuation->ReadComplete(err, aData, aDataSize);
-    delete mContinuation;
+
+    if (IO_SUCCEEDED(aStatus)) {
+      mOnSuccess(aData, aDataSize);
+    } else {
+      mOnFailure();
+    }
+
     delete this;
   }
 
-  GMPRecord* mRecord;
-  ReadContinuation* mContinuation;
+  FileIO* mFileIO = nullptr;
+
+  function<void(const uint8_t*, uint32_t)> mOnSuccess;
+  function<void()> mOnFailure;
 };
 
 void
-ReadData(const std::string& aRecordName,
-         ReadContinuation* aContinuation)
+ReadData(Host_8* mHost,
+         string& aRecordName,
+         function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
+         function<void()>&& aOnFailure)
 {
-  ReadRecordClient::Read(aRecordName, aContinuation);
+  ReadRecordClient::Read(mHost,
+                         aRecordName,
+                         move(aOnSuccess),
+                         move(aOnFailure));
 }
-
-GMPErr
-EnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc)
-{
-  return GetPlatform()->getrecordenumerator(aRecvIteratorFunc, nullptr);
-}
--- a/media/gmp-clearkey/0.1/ClearKeyStorage.h
+++ b/media/gmp-clearkey/0.1/ClearKeyStorage.h
@@ -12,37 +12,32 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __ClearKeyStorage_h__
 #define __ClearKeyStorage_h__
 
-#include "gmp-api/gmp-errors.h"
-#include "gmp-api/gmp-platform.h"
+#include <functional>
+#include <stdint.h>
 #include <string>
 #include <vector>
-#include <stdint.h>
 
-class GMPTask;
+#include "ClearKeySessionManager.h"
 
-// Responsible for ensuring that both aOnSuccess and aOnFailure are destroyed.
-void StoreData(const std::string& aRecordName,
-               const std::vector<uint8_t>& aData,
-               GMPTask* aOnSuccess,
-               GMPTask* aOnFailure);
+#define IO_SUCCEEDED(x) ((x) == cdm::FileIOClient::Status::kSuccess)
+#define IO_FAILED(x) ((x) != cdm::FileIOClient::Status::kSuccess)
 
-class ReadContinuation {
-public:
-  virtual void ReadComplete(GMPErr aStatus,
-                            const uint8_t* aData,
-                            uint32_t aLength) = 0;
-  virtual ~ReadContinuation() {}
-};
+// Writes data to a file and fires the appropriate callback when complete.
+void WriteData(cdm::Host_8* aHost,
+               std::string& aRecordName,
+               const std::vector<uint8_t>& aData,
+               std::function<void()>&& aOnSuccess,
+               std::function<void()>&& aOnFailure);
 
-// Deletes aContinuation after running it to report the result.
-void ReadData(const std::string& aSessionId,
-              ReadContinuation* aContinuation);
-
-GMPErr EnumRecordNames(RecvGMPRecordIteratorPtr aRecvIteratorFunc);
+// Reads data from a file and fires the appropriate callback when complete.
+void ReadData(cdm::Host_8* aHost,
+              std::string& aRecordName,
+              std::function<void(const uint8_t*, uint32_t)>&& aOnSuccess,
+              std::function<void()>&& aOnFailure);
 
 #endif // __ClearKeyStorage_h__
--- a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp
@@ -9,43 +9,87 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
+#include "ClearKeyUtils.h"
+
 #include <algorithm>
+#include <assert.h>
+#include <stdlib.h>
+#include <cctype>
 #include <ctype.h>
+#include <memory.h>
+#include <sstream>
 #include <stdarg.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <vector>
 
-#include "ClearKeyUtils.h"
+#include "ArrayUtils.h"
+#include "BigEndian.h"
 #include "ClearKeyBase64.h"
-#include "ArrayUtils.h"
-#include <assert.h>
-#include <memory.h>
-#include "BigEndian.h"
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
 #include "openaes/oaes_lib.h"
+#include "psshparser/PsshParser.h"
 
+using namespace cdm;
 using namespace std;
 
 void
 CK_Log(const char* aFmt, ...)
 {
+  FILE* out = stdout;
+
+  if (getenv("CLEARKEY_LOG_FILE")) {
+    out = fopen(getenv("CLEARKEY_LOG_FILE"), "a");
+  }
+
   va_list ap;
 
   va_start(ap, aFmt);
-  vprintf(aFmt, ap);
+  const size_t len = 1024;
+  char buf[len];
+  vsnprintf(buf, len, aFmt, ap);
   va_end(ap);
 
-  printf("\n");
-  fflush(stdout);
+  fprintf(out, "%s\n", buf);
+  fflush(out);
+
+  if (out != stdout) {
+    fclose(out);
+  }
+}
+
+static bool
+PrintableAsString(const uint8_t* aBytes, uint32_t aLength)
+{
+  return all_of(aBytes, aBytes + aLength, [] (uint8_t c) {
+    return isprint(c) == 1;
+  });
+}
+
+void
+CK_LogArray(const char* prepend,
+            const uint8_t* aData,
+            const uint32_t aDataSize)
+{
+  // If the data is valid ascii, use that. Otherwise print the hex
+  string data = PrintableAsString(aData, aDataSize) ?
+                string(aData, aData + aDataSize) :
+                ClearKeyUtils::ToHexString(aData, aDataSize);
+
+  CK_LOGD("%s%s", prepend, data.c_str());
 }
 
 static void
 IncrementIV(vector<uint8_t>& aIV) {
   using mozilla::BigEndian;
 
   assert(aIV.size() == 16);
   BigEndian::writeUint64(&aIV[8], BigEndian::readUint64(&aIV[8]) + 1);
@@ -110,27 +154,29 @@ EncodeBase64Web(vector<uint8_t> aBinary,
     }
 
     out[i] += (*data >> (shift + 2)) & sMask;
     shift = (shift + 2) % 8;
 
     // Cast idx to size_t before using it as an array-index,
     // to pacify clang 'Wchar-subscripts' warning:
     size_t idx = static_cast<size_t>(out[i]);
-    assert(idx < MOZ_ARRAY_LENGTH(sAlphabet)); // out of bounds index for 'sAlphabet'
+
+    // out of bounds index for 'sAlphabet'
+    assert(idx < MOZ_ARRAY_LENGTH(sAlphabet));
     out[i] = sAlphabet[idx];
   }
 
   return true;
 }
 
 /* static */ void
 ClearKeyUtils::MakeKeyRequest(const vector<KeyId>& aKeyIDs,
                               string& aOutRequest,
-                              GMPSessionType aSessionType)
+                              SessionType aSessionType)
 {
   assert(aKeyIDs.size() && aOutRequest.empty());
 
   aOutRequest.append("{\"kids\":[");
   for (size_t i = 0; i < aKeyIDs.size(); i++) {
     if (i) {
       aOutRequest.append(",");
     }
@@ -384,17 +430,17 @@ ParseKeys(ParserContext& aCtx, vector<Ke
   }
 
   return GetNextSymbol(aCtx) == ']';
 }
 
 /* static */ bool
 ClearKeyUtils::ParseJWK(const uint8_t* aKeyData, uint32_t aKeyDataSize,
                         vector<KeyIdPair>& aOutKeys,
-                        GMPSessionType aSessionType)
+                        SessionType aSessionType)
 {
   ParserContext ctx;
   ctx.mIter = aKeyData;
   ctx.mEnd = aKeyData + aKeyDataSize;
 
   // Consume '{' from start of object.
   EXPECT_SYMBOL(ctx, '{');
 
@@ -500,25 +546,26 @@ ClearKeyUtils::ParseKeyIdsInitData(const
 
   // Consume '}' from end of object.
   EXPECT_SYMBOL(ctx, '}');
 
   return true;
 }
 
 /* static */ const char*
-ClearKeyUtils::SessionTypeToString(GMPSessionType aSessionType)
+ClearKeyUtils::SessionTypeToString(SessionType aSessionType)
 {
   switch (aSessionType) {
-    case kGMPTemporySession: return "temporary";
-    case kGMPPersistentSession: return "persistent-license";
-    default: {
-      assert(false); // Should not reach here.
-      return "invalid";
-    }
+  case SessionType::kTemporary: return "temporary";
+  case SessionType::kPersistentLicense: return "persistent-license";
+  default: {
+    // We don't support any other license types.
+    assert(false);
+    return "invalid";
+  }
   }
 }
 
 /* static */ bool
 ClearKeyUtils::IsValidSessionId(const char* aBuff, uint32_t aLength)
 {
   if (aLength > 10) {
     // 10 is the max number of characters in UINT32_MAX when
@@ -528,14 +575,20 @@ ClearKeyUtils::IsValidSessionId(const ch
   for (uint32_t i = 0; i < aLength; i++) {
     if (!isdigit(aBuff[i])) {
       return false;
     }
   }
   return true;
 }
 
-GMPMutex* GMPCreateMutex() {
-  GMPMutex* mutex;
-  auto err = GetPlatform()->createmutex(&mutex);
-  assert(mutex);
-  return GMP_FAILED(err) ? nullptr : mutex;
+string
+ClearKeyUtils::ToHexString(const uint8_t * aBytes, uint32_t aLength)
+{
+  stringstream ss;
+  ss << std::showbase << std::uppercase << std::hex;
+  for (uint32_t i = 0; i < aLength; ++i) {
+    ss << std::hex << static_cast<uint32_t>(aBytes[i]);
+    ss << " ";
+  }
+
+  return ss.str();
 }
--- a/media/gmp-clearkey/0.1/ClearKeyUtils.h
+++ b/media/gmp-clearkey/0.1/ClearKeyUtils.h
@@ -16,43 +16,54 @@
 
 #ifndef __ClearKeyUtils_h__
 #define __ClearKeyUtils_h__
 
 #include <stdint.h>
 #include <string>
 #include <vector>
 #include <assert.h>
-#include "gmp-api/gmp-decryption.h"
+
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
 
 #if 0
 void CK_Log(const char* aFmt, ...);
 #define CK_LOGE(...) CK_Log(__VA_ARGS__)
 #define CK_LOGD(...) CK_Log(__VA_ARGS__)
 #define CK_LOGW(...) CK_Log(__VA_ARGS__)
+#define CK_LOGARRAY(APREPEND, ADATA, ADATA_SIZE) CK_LogArray(APREPEND, \
+  ADATA, \
+  ADATA_SIZE)
 #else
+// Note: Enabling logging slows things down a LOT, especially when logging to
+// a file.
 #define CK_LOGE(...)
 #define CK_LOGD(...)
 #define CK_LOGW(...)
+#define CK_LOGARRAY(APREPEND, ADATA, ADATA_SIZE)
 #endif
 
-struct GMPPlatformAPI;
-extern GMPPlatformAPI* GetPlatform();
-
 typedef std::vector<uint8_t> KeyId;
 typedef std::vector<uint8_t> Key;
 
 // The session response size should be within a reasonable limit.
 // The size 64 KB is referenced from web-platform-test.
 static const uint32_t kMaxSessionResponseLength = 65536;
 
 // Provide limitation for KeyIds length and webm initData size.
 static const uint32_t kMaxWebmInitDataSize = 65536;
 static const uint32_t kMaxKeyIdsLength = 512;
 
+void CK_LogArray(const char* aPrepend,
+                 const uint8_t* aData,
+                 const uint32_t aDataSize);
+
 struct KeyIdPair
 {
   KeyId mKeyId;
   Key mKey;
 };
 
 class ClearKeyUtils
 {
@@ -61,54 +72,35 @@ public:
                          std::vector<uint8_t>& aData, std::vector<uint8_t>& aIV);
 
   static bool ParseKeyIdsInitData(const uint8_t* aInitData,
                                   uint32_t aInitDataSize,
                                   std::vector<KeyId>& aOutKeyIds);
 
   static void MakeKeyRequest(const std::vector<KeyId>& aKeyIds,
                              std::string& aOutRequest,
-                             GMPSessionType aSessionType);
+                             cdm::SessionType aSessionType);
 
   static bool ParseJWK(const uint8_t* aKeyData, uint32_t aKeyDataSize,
                        std::vector<KeyIdPair>& aOutKeys,
-                       GMPSessionType aSessionType);
-  static const char* SessionTypeToString(GMPSessionType aSessionType);
+                       cdm::SessionType aSessionType);
+  static const char* SessionTypeToString(cdm::SessionType aSessionType);
 
   static bool IsValidSessionId(const char* aBuff, uint32_t aLength);
+
+  static std::string ToHexString(const uint8_t * aBytes, uint32_t aLength);
 };
 
 template<class Container, class Element>
 inline bool
 Contains(const Container& aContainer, const Element& aElement)
 {
   return aContainer.find(aElement) != aContainer.end();
 }
 
-class AutoLock {
-public:
-  explicit AutoLock(GMPMutex* aMutex)
-    : mMutex(aMutex)
-  {
-    assert(aMutex);
-    if (mMutex) {
-      mMutex->Acquire();
-    }
-  }
-  ~AutoLock() {
-    if (mMutex) {
-      mMutex->Release();
-    }
-  }
-private:
-  GMPMutex* mMutex;
-};
-
-GMPMutex* GMPCreateMutex();
-
 template<typename T>
 inline void
 Assign(std::vector<T>& aVec, const T* aData, size_t aLength)
 {
   aVec.assign(aData, aData + aLength);
 }
 
 #endif // __ClearKeyUtils_h__
--- a/media/gmp-clearkey/0.1/RefCounted.h
+++ b/media/gmp-clearkey/0.1/RefCounted.h
@@ -16,51 +16,17 @@
 
 #ifndef __RefCount_h__
 #define __RefCount_h__
 
 #include <stdint.h>
 #include <assert.h>
 #include "ClearKeyUtils.h"
 
-#if defined(_MSC_VER)
 #include <atomic>
-typedef std::atomic<uint32_t> AtomicRefCount;
-#else
-class AtomicRefCount {
-public:
-  explicit AtomicRefCount(uint32_t aValue)
-    : mCount(aValue)
-    , mMutex(GMPCreateMutex())
-  {
-    assert(mMutex);
-  }
-  ~AtomicRefCount()
-  {
-    if (mMutex) {
-      mMutex->Destroy();
-    }
-  }
-  uint32_t operator--() {
-    AutoLock lock(mMutex);
-    return --mCount;
-  }
-  uint32_t operator++() {
-    AutoLock lock(mMutex);
-    return ++mCount;
-  }
-  operator uint32_t() {
-    AutoLock lock(mMutex);
-    return mCount;
-  }
-private:
-  uint32_t mCount;
-  GMPMutex* mMutex;
-};
-#endif
 
 // Note: Thread safe.
 class RefCounted {
 public:
   void AddRef() {
     ++mRefCount;
   }
 
@@ -76,41 +42,57 @@ protected:
   RefCounted()
     : mRefCount(0)
   {
   }
   virtual ~RefCounted()
   {
     assert(!mRefCount);
   }
-  AtomicRefCount mRefCount;
+  std::atomic<uint32_t> mRefCount;
 };
 
 template<class T>
 class RefPtr {
 public:
-  explicit RefPtr(T* aPtr) : mPtr(nullptr) {
-    Assign(aPtr);
+  RefPtr(const RefPtr& src) {
+    Set(src.mPtr);
   }
+
+  explicit RefPtr(T* aPtr) {
+    Set(aPtr);
+  }
+  RefPtr() { Set(nullptr); }
+
   ~RefPtr() {
-    Assign(nullptr);
+    Set(nullptr);
   }
   T* operator->() const { return mPtr; }
+  T** operator&() { return &mPtr; }
+  T* operator->() { return mPtr; }
+  operator T*() { return mPtr; }
+
+  T* Get() const { return mPtr; }
 
   RefPtr& operator=(T* aVal) {
-    Assign(aVal);
+    Set(aVal);
     return *this;
   }
 
 private:
-  void Assign(T* aPtr) {
+  T* Set(T* aPtr) {
+    if (mPtr == aPtr) {
+      return aPtr;
+    }
     if (mPtr) {
       mPtr->Release();
     }
     mPtr = aPtr;
     if (mPtr) {
       aPtr->AddRef();
     }
+    return mPtr;
   }
-  T* mPtr;
+
+  T* mPtr = nullptr;
 };
 
 #endif // __RefCount_h__
--- a/media/gmp-clearkey/0.1/VideoDecoder.cpp
+++ b/media/gmp-clearkey/0.1/VideoDecoder.cpp
@@ -9,447 +9,310 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
+#include <algorithm>
 #include <cstdint>
 #include <limits>
 
-#include "AnnexB.h"
 #include "BigEndian.h"
 #include "ClearKeyDecryptionManager.h"
 #include "ClearKeyUtils.h"
-#include "gmp-task-utils.h"
 #include "VideoDecoder.h"
 
 using namespace wmf;
+using namespace cdm;
 
-VideoDecoder::VideoDecoder(GMPVideoHost *aHostAPI)
-  : mHostAPI(aHostAPI)
-  , mCallback(nullptr)
-  , mWorkerThread(nullptr)
-  , mMutex(nullptr)
-  , mNumInputTasks(0)
-  , mSentExtraData(false)
-  , mIsFlushing(false)
+VideoDecoder::VideoDecoder(Host_8 *aHost)
+  : mHost(aHost)
   , mHasShutdown(false)
 {
   // We drop the ref in DecodingComplete().
   AddRef();
+
+  mDecoder = new WMFH264Decoder();
+
+  uint32_t cores = std::max(1u, std::thread::hardware_concurrency());
+  HRESULT hr = mDecoder->Init(cores);
 }
 
 VideoDecoder::~VideoDecoder()
 {
-  if (mMutex) {
-    mMutex->Destroy();
-  }
+
 }
 
-void
-VideoDecoder::InitDecode(const GMPVideoCodec& aCodecSettings,
-                         const uint8_t* aCodecSpecific,
-                         uint32_t aCodecSpecificLength,
-                         GMPVideoDecoderCallback* aCallback,
-                         int32_t aCoreCount)
+Status
+VideoDecoder::InitDecode(const VideoDecoderConfig& aConfig)
 {
-  mCallback = aCallback;
-  assert(mCallback);
-  mDecoder = new WMFH264Decoder();
-  HRESULT hr = mDecoder->Init(aCoreCount);
-  if (FAILED(hr)) {
+  if (!mDecoder) {
     CK_LOGD("VideoDecoder::InitDecode failed to init WMFH264Decoder");
-    mCallback->Error(GMPGenericErr);
-    return;
-  }
 
-  auto err = GetPlatform()->createmutex(&mMutex);
-  if (GMP_FAILED(err)) {
-    CK_LOGD("VideoDecoder::InitDecode failed to create GMPMutex");
-    mCallback->Error(GMPGenericErr);
-    return;
+    return Status::kDecodeError;
   }
 
-  // The first byte is mPacketizationMode, which is only relevant for
-  // WebRTC/OpenH264 usecase.
-  const uint8_t* avcc = aCodecSpecific + 1;
-  const uint8_t* avccEnd = aCodecSpecific + aCodecSpecificLength;
-  mExtraData.insert(mExtraData.end(), avcc, avccEnd);
-
-  AnnexB::ConvertConfig(mExtraData, mAnnexB);
+  return Status::kSuccess;
 }
 
-void
-VideoDecoder::EnsureWorker()
+Status
+VideoDecoder::Decode(const InputBuffer& aInputBuffer, VideoFrame* aVideoFrame)
 {
-  if (!mWorkerThread) {
-    GetPlatform()->createthread(&mWorkerThread);
-    if (!mWorkerThread) {
-      mCallback->Error(GMPAllocErr);
-      return;
-    }
-  }
-}
-
-void
-VideoDecoder::Decode(GMPVideoEncodedFrame* aInputFrame,
-                     bool aMissingFrames,
-                     const uint8_t* aCodecSpecificInfo,
-                     uint32_t aCodecSpecificInfoLength,
-                     int64_t aRenderTimeMs)
-{
-  if (aInputFrame->BufferType() != GMP_BufferLength32) {
-    // Gecko should only send frames with 4 byte NAL sizes to GMPs.
-    mCallback->Error(GMPGenericErr);
-    return;
+  // If the input buffer we have been passed has a null buffer, it means we
+  // should drain.
+  if (!aInputBuffer.data) {
+    // This will drain the decoder until there are no frames left to drain,
+    // whereupon it will return 'NeedsMoreData'.
+    CK_LOGD("Input buffer null: Draining");
+    return Drain(aVideoFrame);
   }
 
-  EnsureWorker();
+  DecodeData* data = new DecodeData();
+  Assign(data->mBuffer, aInputBuffer.data, aInputBuffer.data_size);
+  data->mTimestamp = aInputBuffer.timestamp;
+  data->mCrypto = CryptoMetaData(&aInputBuffer);
 
-  {
-    AutoLock lock(mMutex);
-    mNumInputTasks++;
+  CK_LOGD("VideoDecoder::DecodeTask");
+  AutoPtr<DecodeData> d(data);
+  HRESULT hr;
+
+  if (!data || !mDecoder) {
+    CK_LOGE("Decode job not set up correctly!");
+    return Status::kDecodeError;
   }
 
-  // Note: we don't need the codec specific info on a per-frame basis.
-  // It's mostly useful for WebRTC use cases.
+  std::vector<uint8_t>& buffer = data->mBuffer;
 
-  // Make a copy of the data, so we can release aInputFrame ASAP,
-  // to avoid too many shmem handles being held by the GMP process.
-  // If the GMP process holds on to too many shmem handles, the Gecko
-  // side can fail to allocate a shmem to send more input. This is
-  // particularly a problem in Gecko mochitests, which can open multiple
-  // actors at once which share the same pool of shmems.
-  DecodeData* data = new DecodeData();
-  Assign(data->mBuffer, aInputFrame->Buffer(), aInputFrame->Size());
-  data->mTimestamp = aInputFrame->TimeStamp();
-  data->mDuration = aInputFrame->Duration();
-  data->mIsKeyframe = (aInputFrame->FrameType() == kGMPKeyFrame);
-  const GMPEncryptedBufferMetadata* crypto = aInputFrame->GetDecryptionData();
-  if (crypto) {
-    data->mCrypto.Init(crypto);
-  }
-  aInputFrame->Destroy();
-  mWorkerThread->Post(WrapTaskRefCounted(this,
-                                         &VideoDecoder::DecodeTask,
-                                         data));
-}
-
-void
-VideoDecoder::DecodeTask(DecodeData* aData)
-{
-  CK_LOGD("VideoDecoder::DecodeTask");
-  AutoPtr<DecodeData> d(aData);
-  HRESULT hr;
+  if (data->mCrypto.IsValid()) {
+    Status rv =
+      ClearKeyDecryptionManager::Get()->Decrypt(buffer, data->mCrypto);
 
-  {
-    AutoLock lock(mMutex);
-    mNumInputTasks--;
-    assert(mNumInputTasks >= 0);
-  }
-
-  if (mIsFlushing) {
-    CK_LOGD("VideoDecoder::DecodeTask rejecting frame: flushing.");
-    return;
-  }
-
-  if (!aData || !mHostAPI || !mDecoder) {
-    CK_LOGE("Decode job not set up correctly!");
-    return;
-  }
-
-  std::vector<uint8_t>& buffer = aData->mBuffer;
-  if (aData->mCrypto.IsValid()) {
-    // Plugin host should have set up its decryptor/key sessions
-    // before trying to decode!
-    GMPErr rv =
-      ClearKeyDecryptionManager::Get()->Decrypt(buffer, aData->mCrypto);
-
-    if (GMP_FAILED(rv)) {
-      MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::Error, rv));
-      return;
+    if (STATUS_FAILED(rv)) {
+      CK_LOGARRAY("Failed to decrypt video using key ",
+                  aInputBuffer.key_id,
+                  aInputBuffer.key_id_size);
+      return rv;
     }
   }
 
-  AnnexB::ConvertFrameInPlace(buffer);
-
-  if (aData->mIsKeyframe) {
-    // We must send the SPS and PPS to Windows Media Foundation's decoder.
-    // Note: We do this *after* decryption, otherwise the subsample info
-    // would be incorrect.
-    buffer.insert(buffer.begin(), mAnnexB.begin(), mAnnexB.end());
-  }
-
   hr = mDecoder->Input(buffer.data(),
                        buffer.size(),
-                       aData->mTimestamp,
-                       aData->mDuration);
+                       data->mTimestamp);
 
   CK_LOGD("VideoDecoder::DecodeTask() Input ret hr=0x%x\n", hr);
+
+
   if (FAILED(hr)) {
+    assert(hr != MF_E_TRANSFORM_NEED_MORE_INPUT);
+
     CK_LOGE("VideoDecoder::DecodeTask() decode failed ret=0x%x%s\n",
-        hr,
-        ((hr == MF_E_NOTACCEPTING) ? " (MF_E_NOTACCEPTING)" : ""));
-    return;
+      hr,
+      ((hr == MF_E_NOTACCEPTING) ? " (MF_E_NOTACCEPTING)" : ""));
+    CK_LOGD("Decode failed. The decoder is not accepting input");
+    return Status::kDecodeError;
   }
 
-  while (hr == S_OK) {
+  return OutputFrame(aVideoFrame);
+}
+
+Status VideoDecoder::OutputFrame(VideoFrame* aVideoFrame) {
+  HRESULT hr = S_OK;
+
+  // Read all the output from the decoder. Ideally, this would be a while loop
+  // where we read the output and check the result as the condition. However,
+  // this produces a memory leak connected to assigning a new CComPtr to the
+  // address of the old one, which avoids the CComPtr cleaning up.
+  while (true) {
     CComPtr<IMFSample> output;
     hr = mDecoder->Output(&output);
-    CK_LOGD("VideoDecoder::DecodeTask() output ret=0x%x\n", hr);
-    if (hr == S_OK) {
-      MaybeRunOnMainThread(
-        WrapTaskRefCounted(this,
-                           &VideoDecoder::ReturnOutput,
-                           CComPtr<IMFSample>(output),
-                           mDecoder->GetFrameWidth(),
-                           mDecoder->GetFrameHeight(),
-                           mDecoder->GetStride()));
+
+    if (hr != S_OK) {
+      break;
     }
-    if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
-      AutoLock lock(mMutex);
-      if (mNumInputTasks == 0) {
-        // We have run all input tasks. We *must* notify Gecko so that it will
-        // send us more data.
-        MaybeRunOnMainThread(
-          WrapTask(mCallback,
-                   &GMPVideoDecoderCallback::InputDataExhausted));
-      }
-    }
-    if (FAILED(hr)) {
-      CK_LOGE("VideoDecoder::DecodeTask() output failed hr=0x%x\n", hr);
-    }
+
+    CK_LOGD("VideoDecoder::DecodeTask() output ret=0x%x\n", hr);
+
+    mOutputQueue.push(output);
+    CK_LOGD("Queue size: %u", mOutputQueue.size());
   }
-}
 
-void
-VideoDecoder::ReturnOutput(IMFSample* aSample,
-                           int32_t aWidth,
-                           int32_t aHeight,
-                           int32_t aStride)
-{
-  CK_LOGD("[%p] VideoDecoder::ReturnOutput()\n", this);
-  assert(aSample);
-
-  HRESULT hr;
-
-  GMPVideoFrame* f = nullptr;
-  auto err = mHostAPI->CreateFrame(kGMPI420VideoFrame, &f);
-  if (GMP_FAILED(err) || !f) {
-    CK_LOGE("Failed to create i420 frame!\n");
-    return;
-  }
-  if (HasShutdown()) {
-    // Note: GMPVideoHost::CreateFrame() can process messages before returning,
-    // including a message that calls VideoDecoder::DecodingComplete(), i.e.
-    // we can shutdown during the call!
-    CK_LOGD("Shutdown while waiting on GMPVideoHost::CreateFrame()!\n");
-    f->Destroy();
-    return;
+  // If we don't have any inputs, we need more data.
+  if (mOutputQueue.empty()) {
+    CK_LOGD("Decode failed. Not enought data; Requesting more input");
+    return Status::kNeedMoreData;
   }
 
-  auto vf = static_cast<GMPVideoi420Frame*>(f);
+  // We will get a MF_E_TRANSFORM_NEED_MORE_INPUT every time, as we always
+  // consume everything in the buffer.
+  if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT && FAILED(hr)) {
+    CK_LOGD("Decode failed output ret=0x%x\n", hr);
+    return Status::kDecodeError;
+  }
+
+  CComPtr<IMFSample> result = mOutputQueue.front();
+  mOutputQueue.pop();
 
-  hr = SampleToVideoFrame(aSample, aWidth, aHeight, aStride, vf);
-  ENSURE(SUCCEEDED(hr), /*void*/);
+  // The Chromium CDM API doesn't have support for negative strides, though
+  // they are theoretically possible in real world data.
+  if (mDecoder->GetStride() <= 0) {
+    return Status::kDecodeError;
+  }
 
-  mCallback->Decoded(vf);
+  hr = SampleToVideoFrame(result,
+                          mDecoder->GetFrameWidth(),
+                          mDecoder->GetFrameHeight(),
+                          mDecoder->GetStride(),
+                          aVideoFrame);
+  if (FAILED(hr)) {
+    return Status::kDecodeError;
+  }
+
+  CK_LOGD("Decode succeeded.");
+  return Status::kSuccess;
 }
 
 HRESULT
 VideoDecoder::SampleToVideoFrame(IMFSample* aSample,
                                  int32_t aWidth,
                                  int32_t aHeight,
                                  int32_t aStride,
-                                 GMPVideoi420Frame* aVideoFrame)
+                                 VideoFrame* aVideoFrame)
 {
+  CK_LOGD("[%p] VideoDecoder::SampleToVideoFrame()\n", this);
+  assert(aSample);
+
   ENSURE(aSample != nullptr, E_POINTER);
   ENSURE(aVideoFrame != nullptr, E_POINTER);
 
   HRESULT hr;
   CComPtr<IMFMediaBuffer> mediaBuffer;
 
+  aVideoFrame->SetFormat(kI420);
+
   // Must convert to contiguous mediaBuffer to use IMD2DBuffer interface.
   hr = aSample->ConvertToContiguousBuffer(&mediaBuffer);
   ENSURE(SUCCEEDED(hr), hr);
 
   // Try and use the IMF2DBuffer interface if available, otherwise fallback
   // to the IMFMediaBuffer interface. Apparently IMF2DBuffer is more efficient,
   // but only some systems (Windows 8?) support it.
   BYTE* data = nullptr;
   LONG stride = 0;
   CComPtr<IMF2DBuffer> twoDBuffer;
   hr = mediaBuffer->QueryInterface(static_cast<IMF2DBuffer**>(&twoDBuffer));
   if (SUCCEEDED(hr)) {
     hr = twoDBuffer->Lock2D(&data, &stride);
     ENSURE(SUCCEEDED(hr), hr);
   } else {
-    hr = mediaBuffer->Lock(&data, NULL, NULL);
+    hr = mediaBuffer->Lock(&data, nullptr, nullptr);
     ENSURE(SUCCEEDED(hr), hr);
     stride = aStride;
   }
 
-  // The V and U planes are stored 16-row-aligned, so we need to add padding
+  // The U and V planes are stored 16-row-aligned, so we need to add padding
   // to the row heights to ensure the Y'CbCr planes are referenced properly.
-  // YV12, planar format: [YYYY....][VVVV....][UUUU....]
-  // i.e., Y, then V, then U.
+  // YV12, planar format: [YYYY....][UUUU....][VVVV....]
+  // i.e., Y, then U, then V.
   uint32_t padding = 0;
   if (aHeight % 16 != 0) {
     padding = 16 - (aHeight % 16);
   }
-  int32_t y_size = stride * (aHeight + padding);
-  int32_t v_size = stride * (aHeight + padding) / 4;
-  int32_t halfStride = (stride + 1) / 2;
-  int32_t halfHeight = (aHeight + 1) / 2;
+  uint32_t ySize = stride * (aHeight + padding);
+  uint32_t uSize = stride * (aHeight + padding) / 4;
+  uint32_t halfStride = (stride + 1) / 2;
+  uint32_t halfHeight = (aHeight + 1) / 2;
+
+  aVideoFrame->SetStride(VideoFrame::kYPlane, stride);
+  aVideoFrame->SetStride(VideoFrame::kUPlane, halfStride);
+  aVideoFrame->SetStride(VideoFrame::kVPlane, halfStride);
 
-  auto err = aVideoFrame->CreateEmptyFrame(stride, aHeight, stride, halfStride, halfStride);
-  ENSURE(GMP_SUCCEEDED(err), E_FAIL);
+  aVideoFrame->SetSize(Size(aWidth, aHeight));
+
+  uint64_t bufferSize = ySize + 2 * uSize;
 
-  err = aVideoFrame->SetWidth(aWidth);
-  ENSURE(GMP_SUCCEEDED(err), E_FAIL);
-  err = aVideoFrame->SetHeight(aHeight);
-  ENSURE(GMP_SUCCEEDED(err), E_FAIL);
+  // If the buffer is bigger than the max for a 32 bit, fail to avoid buffer
+  // overflows.
+  if (bufferSize > UINT32_MAX) {
+    return Status::kDecodeError;
+  }
 
-  uint8_t* outBuffer = aVideoFrame->Buffer(kGMPYPlane);
-  ENSURE(outBuffer != nullptr, E_FAIL);
-  assert(aVideoFrame->AllocatedSize(kGMPYPlane) >= stride*aHeight);
-  memcpy(outBuffer, data, stride*aHeight);
+  // Get the buffer from the host.
+  Buffer* buffer = mHost->Allocate(bufferSize);
+  aVideoFrame->SetFrameBuffer(buffer);
+
+  // Make sure the buffer is non-null (allocate guarantees it will be of
+  // sufficient size).
+  if (!buffer) {
+    return E_OUTOFMEMORY;
+  }
 
-  outBuffer = aVideoFrame->Buffer(kGMPUPlane);
-  ENSURE(outBuffer != nullptr, E_FAIL);
-  assert(aVideoFrame->AllocatedSize(kGMPUPlane) >= halfStride*halfHeight);
-  memcpy(outBuffer, data+y_size, halfStride*halfHeight);
+  uint8_t* outBuffer = buffer->Data();
+
+  aVideoFrame->SetPlaneOffset(VideoFrame::kYPlane, 0);
 
-  outBuffer = aVideoFrame->Buffer(kGMPVPlane);
-  ENSURE(outBuffer != nullptr, E_FAIL);
-  assert(aVideoFrame->AllocatedSize(kGMPVPlane) >= halfStride*halfHeight);
-  memcpy(outBuffer, data + y_size + v_size, halfStride*halfHeight);
+  // Offset is the size of the copied y data.
+  aVideoFrame->SetPlaneOffset(VideoFrame::kUPlane, ySize);
+
+  // Offset is the size of the copied y data + the size of the copied u data.
+  aVideoFrame->SetPlaneOffset(VideoFrame::kVPlane, ySize + uSize);
+
+  // Copy the data.
+  memcpy(outBuffer, data, ySize + uSize * 2);
 
   if (twoDBuffer) {
     twoDBuffer->Unlock2D();
   } else {
     mediaBuffer->Unlock();
   }
 
   LONGLONG hns = 0;
   hr = aSample->GetSampleTime(&hns);
   ENSURE(SUCCEEDED(hr), hr);
+
   aVideoFrame->SetTimestamp(HNsToUsecs(hns));
 
-  hr = aSample->GetSampleDuration(&hns);
-  ENSURE(SUCCEEDED(hr), hr);
-  aVideoFrame->SetDuration(HNsToUsecs(hns));
-
   return S_OK;
 }
 
 void
-VideoDecoder::ResetCompleteTask()
-{
-  mIsFlushing = false;
-  if (mCallback) {
-    MaybeRunOnMainThread(WrapTask(mCallback,
-                                  &GMPVideoDecoderCallback::ResetComplete));
-  }
-}
-
-void
 VideoDecoder::Reset()
 {
-  mIsFlushing = true;
+  CK_LOGD("VideoDecoder::Reset");
+
   if (mDecoder) {
     mDecoder->Reset();
   }
 
-  // Schedule ResetComplete callback to run after existing frames have been
-  // flushed out of the task queue.
-  EnsureWorker();
-  mWorkerThread->Post(WrapTaskRefCounted(this,
-                                         &VideoDecoder::ResetCompleteTask));
+  // Remove all the frames from the output queue.
+  while (!mOutputQueue.empty()) {
+    mOutputQueue.pop();
+  }
 }
 
-void
-VideoDecoder::DrainTask()
+Status
+VideoDecoder::Drain(VideoFrame* aVideoFrame)
 {
+  CK_LOGD("VideoDecoder::Drain()");
+
+  if (!mDecoder) {
+    CK_LOGD("Drain failed! Decoder was not initialized");
+    return Status::kDecodeError;
+  }
+
   mDecoder->Drain();
 
   // Return any pending output.
-  HRESULT hr = S_OK;
-  while (hr == S_OK) {
-    CComPtr<IMFSample> output;
-    hr = mDecoder->Output(&output);
-    CK_LOGD("VideoDecoder::DrainTask() output ret=0x%x\n", hr);
-    if (hr == S_OK) {
-      MaybeRunOnMainThread(
-        WrapTaskRefCounted(this,
-                           &VideoDecoder::ReturnOutput,
-                           CComPtr<IMFSample>(output),
-                           mDecoder->GetFrameWidth(),
-                           mDecoder->GetFrameHeight(),
-                           mDecoder->GetStride()));
-    }
-  }
-  MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::DrainComplete));
-}
-
-void
-VideoDecoder::Drain()
-{
-  if (!mDecoder) {
-    if (mCallback) {
-      mCallback->DrainComplete();
-    }
-    return;
-  }
-  EnsureWorker();
-  mWorkerThread->Post(WrapTaskRefCounted(this,
-                                         &VideoDecoder::DrainTask));
+  return OutputFrame(aVideoFrame);
 }
 
 void
 VideoDecoder::DecodingComplete()
 {
-  if (mWorkerThread) {
-    mWorkerThread->Join();
-  }
   mHasShutdown = true;
 
   // Release the reference we added in the constructor. There may be
   // WrapRefCounted tasks that also hold references to us, and keep
   // us alive a little longer.
   Release();
 }
-
-void
-VideoDecoder::MaybeRunOnMainThread(GMPTask* aTask)
-{
-  class MaybeRunTask : public GMPTask
-  {
-  public:
-    MaybeRunTask(VideoDecoder* aDecoder, GMPTask* aTask)
-      : mDecoder(aDecoder), mTask(aTask)
-    { }
-
-    virtual void Run(void) {
-      if (mDecoder->HasShutdown()) {
-        CK_LOGD("Trying to dispatch to main thread after VideoDecoder has shut down");
-        return;
-      }
-
-      mTask->Run();
-    }
-
-    virtual void Destroy()
-    {
-      mTask->Destroy();
-      delete this;
-    }
-
-  private:
-    RefPtr<VideoDecoder> mDecoder;
-    GMPTask* mTask;
-  };
-
-  GetPlatform()->runonmainthread(new MaybeRunTask(this, aTask));
-}
--- a/media/gmp-clearkey/0.1/VideoDecoder.h
+++ b/media/gmp-clearkey/0.1/VideoDecoder.h
@@ -13,98 +13,62 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef __VideoDecoder_h__
 #define __VideoDecoder_h__
 
 #include <atomic>
+#include <queue>
+#include <thread>
 
-#include "gmp-task-utils.h"
-#include "gmp-video-decode.h"
-#include "gmp-video-host.h"
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
 #include "WMFH264Decoder.h"
 
-#include "mfobjects.h"
-
-class VideoDecoder : public GMPVideoDecoder
-                   , public RefCounted
+class VideoDecoder : public RefCounted
 {
 public:
-  explicit VideoDecoder(GMPVideoHost *aHostAPI);
+  explicit VideoDecoder(cdm::Host_8 *aHost);
 
-  virtual void InitDecode(const GMPVideoCodec& aCodecSettings,
-                          const uint8_t* aCodecSpecific,
-                          uint32_t aCodecSpecificLength,
-                          GMPVideoDecoderCallback* aCallback,
-                          int32_t aCoreCount) override;
+  cdm::Status InitDecode(const cdm::VideoDecoderConfig& aConfig);
 
-  virtual void Decode(GMPVideoEncodedFrame* aInputFrame,
-                      bool aMissingFrames,
-                      const uint8_t* aCodecSpecific,
-                      uint32_t aCodecSpecificLength,
-                      int64_t aRenderTimeMs = -1);
+  cdm::Status Decode(const cdm::InputBuffer& aEncryptedBuffer,
+                     cdm::VideoFrame* aVideoFrame);
 
-  virtual void Reset() override;
+  void Reset();
 
-  virtual void Drain() override;
-
-  virtual void DecodingComplete() override;
+  void DecodingComplete();
 
   bool HasShutdown() { return mHasShutdown; }
 
 private:
 
   virtual ~VideoDecoder();
 
-  void EnsureWorker();
-
-  void DrainTask();
+  cdm::Status Drain(cdm::VideoFrame* aVideoFrame);
 
   struct DecodeData {
-    DecodeData()
-      : mTimestamp(0)
-      , mDuration(0)
-      , mIsKeyframe(false)
-    {}
     std::vector<uint8_t> mBuffer;
-    uint64_t mTimestamp;
-    uint64_t mDuration;
-    bool mIsKeyframe;
+    uint64_t mTimestamp = 0;
     CryptoMetaData mCrypto;
   };
 
-  void DecodeTask(DecodeData* aData);
-
-  void ResetCompleteTask();
-
-  void ReturnOutput(IMFSample* aSample,
-                    int32_t aWidth,
-                    int32_t aHeight,
-                    int32_t aStride);
+  cdm::Status OutputFrame(cdm::VideoFrame* aVideoFrame);
 
   HRESULT SampleToVideoFrame(IMFSample* aSample,
                              int32_t aWidth,
                              int32_t aHeight,
                              int32_t aStride,
-                             GMPVideoi420Frame* aVideoFrame);
-
-  void MaybeRunOnMainThread(GMPTask* aTask);
+                             cdm::VideoFrame* aVideoFrame);
 
-  GMPVideoHost *mHostAPI; // host-owned, invalid at DecodingComplete
-  GMPVideoDecoderCallback* mCallback; // host-owned, invalid at DecodingComplete
-  GMPThread* mWorkerThread;
-  GMPMutex* mMutex;
+  cdm::Host_8* mHost;
   wmf::AutoPtr<wmf::WMFH264Decoder> mDecoder;
 
-  std::vector<uint8_t> mExtraData;
-  std::vector<uint8_t> mAnnexB;
-
-  int32_t mNumInputTasks;
-  bool mSentExtraData;
-
-  std::atomic<bool> mIsFlushing;
+  std::queue<wmf::CComPtr<IMFSample>> mOutputQueue;
 
   bool mHasShutdown;
 };
 
 #endif // __VideoDecoder_h__
--- a/media/gmp-clearkey/0.1/WMFH264Decoder.cpp
+++ b/media/gmp-clearkey/0.1/WMFH264Decoder.cpp
@@ -191,17 +191,16 @@ WMFH264Decoder::SendMFTMessage(MFT_MESSA
   ENSURE(SUCCEEDED(hr), hr);
   return S_OK;
 }
 
 HRESULT
 WMFH264Decoder::CreateInputSample(const uint8_t* aData,
                                   uint32_t aDataSize,
                                   Microseconds aTimestamp,
-                                  Microseconds aDuration,
                                   IMFSample** aOutSample)
 {
   HRESULT hr;
   CComPtr<IMFSample> sample;
   hr = MFCreateSample(&sample);
   ENSURE(SUCCEEDED(hr), hr);
 
   CComPtr<IMFMediaBuffer> buffer;
@@ -226,18 +225,16 @@ WMFH264Decoder::CreateInputSample(const 
   ENSURE(SUCCEEDED(hr), hr);
 
   hr = sample->AddBuffer(buffer);
   ENSURE(SUCCEEDED(hr), hr);
 
   hr = sample->SetSampleTime(UsecsToHNs(aTimestamp));
   ENSURE(SUCCEEDED(hr), hr);
 
-  sample->SetSampleDuration(UsecsToHNs(aDuration));
-
   *aOutSample = sample.Detach();
 
   return S_OK;
 }
 
 HRESULT
 WMFH264Decoder::CreateOutputSample(IMFSample** aOutSample)
 {
@@ -296,22 +293,21 @@ WMFH264Decoder::GetOutputSample(IMFSampl
   // output.pSample
   *aOutSample = sample.Detach(); // AddRefs
   return S_OK;
 }
 
 HRESULT
 WMFH264Decoder::Input(const uint8_t* aData,
                       uint32_t aDataSize,
-                      Microseconds aTimestamp,
-                      Microseconds aDuration)
+                      Microseconds aTimestamp)
 {
   HRESULT hr;
   CComPtr<IMFSample> input = nullptr;
-  hr = CreateInputSample(aData, aDataSize, aTimestamp, aDuration, &input);
+  hr = CreateInputSample(aData, aDataSize, aTimestamp, &input);
   ENSURE(SUCCEEDED(hr) && input!=nullptr, hr);
 
   hr = mDecoder->ProcessInput(0, input, 0);
   if (hr == MF_E_NOTACCEPTING) {
     // MFT *already* has enough data to produce a sample. Retrieve it.
     LOG("ProcessInput returned MF_E_NOTACCEPTING\n");
     return MF_E_NOTACCEPTING;
   }
--- a/media/gmp-clearkey/0.1/WMFH264Decoder.h
+++ b/media/gmp-clearkey/0.1/WMFH264Decoder.h
@@ -25,18 +25,17 @@ class WMFH264Decoder {
 public:
   WMFH264Decoder();
   ~WMFH264Decoder();
 
   HRESULT Init(int32_t aCoreCount);
 
   HRESULT Input(const uint8_t* aData,
                 uint32_t aDataSize,
-                Microseconds aTimestamp,
-                Microseconds aDuration);
+                Microseconds aTimestamp);
 
   HRESULT Output(IMFSample** aOutput);
 
   HRESULT Reset();
 
   int32_t GetFrameWidth() const;
   int32_t GetFrameHeight() const;
   const IntRect& GetPictureRegion() const;
@@ -48,17 +47,16 @@ private:
 
   HRESULT SetDecoderInputType();
   HRESULT SetDecoderOutputType();
   HRESULT SendMFTMessage(MFT_MESSAGE_TYPE aMsg, UINT32 aData);
 
   HRESULT CreateInputSample(const uint8_t* aData,
                             uint32_t aDataSize,
                             Microseconds aTimestamp,
-                            Microseconds aDuration,
                             IMFSample** aOutSample);
 
   HRESULT CreateOutputSample(IMFSample** aOutSample);
 
   HRESULT GetOutputSample(IMFSample** aOutSample);
   HRESULT ConfigureVideoFrameGeometry(IMFMediaType* aMediaType);
 
   MFT_INPUT_STREAM_INFO mInputStreamInfo;
--- a/media/gmp-clearkey/0.1/WMFUtils.h
+++ b/media/gmp-clearkey/0.1/WMFUtils.h
@@ -114,18 +114,18 @@ typedef int64_t Microseconds;
 
 #ifdef ENSURE
 #undef ENSURE
 #endif
 
 #define ENSURE(condition, ret) \
 { if (!(condition)) { LOG("##condition## FAILED %S:%d\n", __FILE__, __LINE__); return ret; } }
 
-#define GMP_SUCCEEDED(x) ((x) == GMPNoErr)
-#define GMP_FAILED(x) ((x) != GMPNoErr)
+#define STATUS_SUCCEEDED(x) ((x) == Status::kSuccess)
+#define STATUS_FAILED(x) ((x) != Status::kSuccess)
 
 #define MFPLAT_FUNC(_func, _dllname) \
   extern decltype(::_func)* _func;
 #include "WMFSymbols.h"
 #undef MFPLAT_FUNC
 
 bool
 EnsureLibs();
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/clearkey.info.in
+++ /dev/null
@@ -1,10 +0,0 @@
-Name: clearkey
-Description: ClearKey Gecko Media Plugin
-Version: 1
-#ifdef ENABLE_WMF
-APIs: eme-decrypt-v9[org.w3.clearkey], decode-video[h264:org.w3.clearkey]
-Libraries: dxva2.dll, d3d9.dll, msmpeg2vdec.dll, msmpeg2adec.dll, MSAudDecMFT.dll, evr.dll, mfheaacdec.dll, mfh264dec.dll, mfplat.dll
-#else
-APIs: eme-decrypt-v9[org.w3.clearkey]
-Libraries:
-#endif
--- a/media/gmp-clearkey/0.1/gmp-clearkey.cpp
+++ b/media/gmp-clearkey/0.1/gmp-clearkey.cpp
@@ -13,73 +13,52 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
-#include "ClearKeyAsyncShutdown.h"
+#include "ClearKeyCDM.h"
 #include "ClearKeySessionManager.h"
-#include "gmp-api/gmp-async-shutdown.h"
-#include "gmp-api/gmp-decryption.h"
-#include "gmp-api/gmp-platform.h"
-
-#if defined(ENABLE_WMF)
-#include "WMFUtils.h"
-#include "VideoDecoder.h"
-#endif
+// This include is required in order for content_decryption_module to work
+// on Unix systems.
+#include "stddef.h"
+#include "content_decryption_module.h"
 
-#if defined(WIN32)
-#define GMP_EXPORT __declspec(dllexport)
-#else
-#define GMP_EXPORT __attribute__((visibility("default")))
-#endif
-
-static GMPPlatformAPI* sPlatform = nullptr;
-GMPPlatformAPI*
-GetPlatform()
-{
-  return sPlatform;
-}
+#ifdef ENABLE_WMF
+#include "WMFUtils.h"
+#endif // ENABLE_WMF
 
 extern "C" {
 
-GMP_EXPORT GMPErr
-GMPInit(GMPPlatformAPI* aPlatformAPI)
-{
-  sPlatform = aPlatformAPI;
-  return GMPNoErr;
+CDM_EXPORT
+void INITIALIZE_CDM_MODULE() {
+
 }
 
-GMP_EXPORT GMPErr
-GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginAPI)
+CDM_EXPORT
+void* CreateCdmInstance(int cdm_interface_version,
+                        const char* key_system,
+                        uint32_t key_system_size,
+                        GetCdmHostFunc get_cdm_host_func,
+                        void* user_data)
 {
-  CK_LOGD("ClearKey GMPGetAPI |%s|", aApiName);
-  assert(!*aPluginAPI);
 
-  if (!strcmp(aApiName, GMP_API_DECRYPTOR)) {
-    *aPluginAPI = new ClearKeySessionManager();
-  }
-#if defined(ENABLE_WMF)
- else if (!strcmp(aApiName, GMP_API_VIDEO_DECODER) &&
-             wmf::EnsureLibs()) {
-    *aPluginAPI = new VideoDecoder(static_cast<GMPVideoHost*>(aHostAPI));
+  CK_LOGE("ClearKey CreateCDMInstance");
+
+#ifdef ENABLE_WMF
+  if (!wmf::EnsureLibs()) {
+    CK_LOGE("Required libraries were not found");
+    return nullptr;
   }
 #endif
-  else if (!strcmp(aApiName, GMP_API_ASYNC_SHUTDOWN)) {
-    *aPluginAPI = new ClearKeyAsyncShutdown(static_cast<GMPAsyncShutdownHost*> (aHostAPI));
-  } else {
-    CK_LOGE("GMPGetAPI couldn't resolve API name |%s|\n", aApiName);
-  }
 
-  return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr;
-}
+  cdm::Host_8* host = static_cast<cdm::Host_8*>(
+    get_cdm_host_func(cdm_interface_version, user_data));
+  ClearKeyCDM* clearKey = new ClearKeyCDM(host);
 
-GMP_EXPORT GMPErr
-GMPShutdown(void)
-{
-  CK_LOGD("ClearKey GMPShutdown");
-  return GMPNoErr;
+  CK_LOGE("Created ClearKeyCDM instance!");
+
+  return clearKey;
 }
-
 }
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/gmp-task-utils-generated.h
+++ /dev/null
@@ -1,1938 +0,0 @@
-/*
- * Copyright 2015, Mozilla Foundation and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "RefCounted.h"
-
-// 0 arguments --
-template<typename M> class gmp_task_args_nm_0 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_0(M m) :
-    m_(m)  {}
-
-  void Run() {
-    m_();
-  }
-
- private:
-  M m_;
-};
-
-
-
-// 0 arguments --
-template<typename M, typename R> class gmp_task_args_nm_0_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_0_ret(M m, R *r) :
-    m_(m), r_(r)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_();
-  }
-
- private:
-  M m_;
-  R* r_;
-};
-
-
-
-// 0 arguments --
-template<typename C, typename M> class gmp_task_args_m_0 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_0(C o, M m) :
-    o_(o), m_(m)  {}
-
-  void Run() {
-    ((*o_).*m_)();
-  }
-
- private:
-  C o_;
-  M m_;
-};
-
-
-
-// 0 arguments --
-template<typename C, typename M, typename R> class gmp_task_args_m_0_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_0_ret(C o, M m, R *r) :
-    o_(o), m_(m), r_(r)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)();
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-};
-
-
-
-// 1 arguments --
-template<typename M, typename A0> class gmp_task_args_nm_1 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_1(M m, A0 a0) :
-    m_(m), a0_(a0)  {}
-
-  void Run() {
-    m_(a0_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-};
-
-
-
-// 1 arguments --
-template<typename M, typename A0, typename R> class gmp_task_args_nm_1_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_1_ret(M m, A0 a0, R *r) :
-    m_(m), r_(r), a0_(a0)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-};
-
-
-
-// 1 arguments --
-template<typename C, typename M, typename A0> class gmp_task_args_m_1 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_1(C o, M m, A0 a0) :
-    o_(o), m_(m), a0_(a0)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-};
-
-
-
-// 1 arguments --
-template<typename C, typename M, typename A0, typename R> class gmp_task_args_m_1_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_1_ret(C o, M m, A0 a0, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-};
-
-
-
-// 2 arguments --
-template<typename M, typename A0, typename A1> class gmp_task_args_nm_2 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_2(M m, A0 a0, A1 a1) :
-    m_(m), a0_(a0), a1_(a1)  {}
-
-  void Run() {
-    m_(a0_, a1_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-};
-
-
-
-// 2 arguments --
-template<typename M, typename A0, typename A1, typename R> class gmp_task_args_nm_2_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_2_ret(M m, A0 a0, A1 a1, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-};
-
-
-
-// 2 arguments --
-template<typename C, typename M, typename A0, typename A1> class gmp_task_args_m_2 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_2(C o, M m, A0 a0, A1 a1) :
-    o_(o), m_(m), a0_(a0), a1_(a1)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-};
-
-
-
-// 2 arguments --
-template<typename C, typename M, typename A0, typename A1, typename R> class gmp_task_args_m_2_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_2_ret(C o, M m, A0 a0, A1 a1, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-};
-
-
-
-// 3 arguments --
-template<typename M, typename A0, typename A1, typename A2> class gmp_task_args_nm_3 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_3(M m, A0 a0, A1 a1, A2 a2) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-};
-
-
-
-// 3 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename R> class gmp_task_args_nm_3_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_3_ret(M m, A0 a0, A1 a1, A2 a2, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-};
-
-
-
-// 3 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2> class gmp_task_args_m_3 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_3(C o, M m, A0 a0, A1 a1, A2 a2) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-};
-
-
-
-// 3 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename R> class gmp_task_args_m_3_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_3_ret(C o, M m, A0 a0, A1 a1, A2 a2, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-};
-
-
-
-// 4 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3> class gmp_task_args_nm_4 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_4(M m, A0 a0, A1 a1, A2 a2, A3 a3) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-};
-
-
-
-// 4 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename R> class gmp_task_args_nm_4_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_4_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-};
-
-
-
-// 4 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3> class gmp_task_args_m_4 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_4(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-};
-
-
-
-// 4 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename R> class gmp_task_args_m_4_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_4_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-};
-
-
-
-// 5 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4> class gmp_task_args_nm_5 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_5(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-};
-
-
-
-// 5 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R> class gmp_task_args_nm_5_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_5_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-};
-
-
-
-// 5 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4> class gmp_task_args_m_5 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_5(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-};
-
-
-
-// 5 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R> class gmp_task_args_m_5_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_5_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-};
-
-
-
-// 6 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5> class gmp_task_args_nm_6 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_6(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_, a5_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-};
-
-
-
-// 6 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R> class gmp_task_args_nm_6_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_6_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-};
-
-
-
-// 6 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5> class gmp_task_args_m_6 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_6(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-};
-
-
-
-// 6 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R> class gmp_task_args_m_6_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_6_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-};
-
-
-
-// 7 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> class gmp_task_args_nm_7 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_7(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-};
-
-
-
-// 7 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R> class gmp_task_args_nm_7_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_7_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-};
-
-
-
-// 7 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> class gmp_task_args_m_7 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_7(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-};
-
-
-
-// 7 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R> class gmp_task_args_m_7_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_7_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-};
-
-
-
-// 8 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> class gmp_task_args_nm_8 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_8(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-};
-
-
-
-// 8 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R> class gmp_task_args_nm_8_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_8_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-};
-
-
-
-// 8 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> class gmp_task_args_m_8 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_8(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-};
-
-
-
-// 8 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R> class gmp_task_args_m_8_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_8_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-};
-
-
-
-// 9 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> class gmp_task_args_nm_9 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_9(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-};
-
-
-
-// 9 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R> class gmp_task_args_nm_9_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_9_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-};
-
-
-
-// 9 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> class gmp_task_args_m_9 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_9(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-};
-
-
-
-// 9 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R> class gmp_task_args_m_9_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_9_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-};
-
-
-
-// 10 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> class gmp_task_args_nm_10 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_10(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-};
-
-
-
-// 10 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R> class gmp_task_args_nm_10_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_10_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-};
-
-
-
-// 10 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> class gmp_task_args_m_10 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_10(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-};
-
-
-
-// 10 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R> class gmp_task_args_m_10_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_10_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-};
-
-
-
-// 11 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10> class gmp_task_args_nm_11 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_11(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-};
-
-
-
-// 11 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R> class gmp_task_args_nm_11_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_11_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-};
-
-
-
-// 11 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10> class gmp_task_args_m_11 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_11(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-};
-
-
-
-// 11 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R> class gmp_task_args_m_11_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_11_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-};
-
-
-
-// 12 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11> class gmp_task_args_nm_12 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_12(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-};
-
-
-
-// 12 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R> class gmp_task_args_nm_12_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_12_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-};
-
-
-
-// 12 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11> class gmp_task_args_m_12 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_12(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-};
-
-
-
-// 12 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R> class gmp_task_args_m_12_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_12_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-};
-
-
-
-// 13 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12> class gmp_task_args_nm_13 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_13(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-  A12 a12_;
-};
-
-
-
-// 13 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R> class gmp_task_args_nm_13_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_13_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-  A12 a12_;
-};
-
-
-
-// 13 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12> class gmp_task_args_m_13 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_13(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-  A12 a12_;
-};
-
-
-
-// 13 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R> class gmp_task_args_m_13_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_13_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-  A12 a12_;
-};
-
-
-
-// 14 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13> class gmp_task_args_nm_14 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_14(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) :
-    m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
-
-  void Run() {
-    m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
-  }
-
- private:
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-  A12 a12_;
-  A13 a13_;
-};
-
-
-
-// 14 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R> class gmp_task_args_nm_14_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_nm_14_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) :
-    m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
-  }
-
- private:
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-  A12 a12_;
-  A13 a13_;
-};
-
-
-
-// 14 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13> class gmp_task_args_m_14 : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_14(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) :
-    o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
-
-  void Run() {
-    ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
-  }
-
- private:
-  C o_;
-  M m_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-  A12 a12_;
-  A13 a13_;
-};
-
-
-
-// 14 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R> class gmp_task_args_m_14_ret : public gmp_task_args_base {
- public:
-  explicit gmp_task_args_m_14_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) :
-    o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13)  {}
-  virtual bool returns_value() const { return true; }
-
-  void Run() {
-    *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_);
-  }
-
- private:
-  C o_;
-  M m_;
-  R* r_;
-  A0 a0_;
-  A1 a1_;
-  A2 a2_;
-  A3 a3_;
-  A4 a4_;
-  A5 a5_;
-  A6 a6_;
-  A7 a7_;
-  A8 a8_;
-  A9 a9_;
-  A10 a10_;
-  A11 a11_;
-  A12 a12_;
-  A13 a13_;
-};
-
-
-
-
-
-
-// 0 arguments --
-template<typename M>
-gmp_task_args_nm_0<M>* WrapTaskNM(M m) {
-  return new gmp_task_args_nm_0<M>
-    (m);
-}
-
-// 0 arguments --
-template<typename M, typename R>
-gmp_task_args_nm_0_ret<M, R>* WrapTaskNMRet(M m, R* r) {
-  return new gmp_task_args_nm_0_ret<M, R>
-    (m, r);
-}
-
-// 0 arguments --
-template<typename C, typename M>
-gmp_task_args_m_0<C, M>* WrapTask(C o, M m) {
-  return new gmp_task_args_m_0<C, M>
-    (o, m);
-}
-
-// 0 arguments --
-template<typename C, typename M, typename R>
-gmp_task_args_m_0_ret<C, M, R>* WrapTaskRet(C o, M m, R* r) {
-  return new gmp_task_args_m_0_ret<C, M, R>
-    (o, m, r);
-}
-
-// 1 arguments --
-template<typename M, typename A0>
-gmp_task_args_nm_1<M, A0>* WrapTaskNM(M m, A0 a0) {
-  return new gmp_task_args_nm_1<M, A0>
-    (m, a0);
-}
-
-// 1 arguments --
-template<typename M, typename A0, typename R>
-gmp_task_args_nm_1_ret<M, A0, R>* WrapTaskNMRet(M m, A0 a0, R* r) {
-  return new gmp_task_args_nm_1_ret<M, A0, R>
-    (m, a0, r);
-}
-
-// 1 arguments --
-template<typename C, typename M, typename A0>
-gmp_task_args_m_1<C, M, A0>* WrapTask(C o, M m, A0 a0) {
-  return new gmp_task_args_m_1<C, M, A0>
-    (o, m, a0);
-}
-
-// 1 arguments --
-template<typename C, typename M, typename A0, typename R>
-gmp_task_args_m_1_ret<C, M, A0, R>* WrapTaskRet(C o, M m, A0 a0, R* r) {
-  return new gmp_task_args_m_1_ret<C, M, A0, R>
-    (o, m, a0, r);
-}
-
-// 2 arguments --
-template<typename M, typename A0, typename A1>
-gmp_task_args_nm_2<M, A0, A1>* WrapTaskNM(M m, A0 a0, A1 a1) {
-  return new gmp_task_args_nm_2<M, A0, A1>
-    (m, a0, a1);
-}
-
-// 2 arguments --
-template<typename M, typename A0, typename A1, typename R>
-gmp_task_args_nm_2_ret<M, A0, A1, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, R* r) {
-  return new gmp_task_args_nm_2_ret<M, A0, A1, R>
-    (m, a0, a1, r);
-}
-
-// 2 arguments --
-template<typename C, typename M, typename A0, typename A1>
-gmp_task_args_m_2<C, M, A0, A1>* WrapTask(C o, M m, A0 a0, A1 a1) {
-  return new gmp_task_args_m_2<C, M, A0, A1>
-    (o, m, a0, a1);
-}
-
-// 2 arguments --
-template<typename C, typename M, typename A0, typename A1, typename R>
-gmp_task_args_m_2_ret<C, M, A0, A1, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, R* r) {
-  return new gmp_task_args_m_2_ret<C, M, A0, A1, R>
-    (o, m, a0, a1, r);
-}
-
-// 3 arguments --
-template<typename M, typename A0, typename A1, typename A2>
-gmp_task_args_nm_3<M, A0, A1, A2>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2) {
-  return new gmp_task_args_nm_3<M, A0, A1, A2>
-    (m, a0, a1, a2);
-}
-
-// 3 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename R>
-gmp_task_args_nm_3_ret<M, A0, A1, A2, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, R* r) {
-  return new gmp_task_args_nm_3_ret<M, A0, A1, A2, R>
-    (m, a0, a1, a2, r);
-}
-
-// 3 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2>
-gmp_task_args_m_3<C, M, A0, A1, A2>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2) {
-  return new gmp_task_args_m_3<C, M, A0, A1, A2>
-    (o, m, a0, a1, a2);
-}
-
-// 3 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename R>
-gmp_task_args_m_3_ret<C, M, A0, A1, A2, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, R* r) {
-  return new gmp_task_args_m_3_ret<C, M, A0, A1, A2, R>
-    (o, m, a0, a1, a2, r);
-}
-
-// 4 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3>
-gmp_task_args_nm_4<M, A0, A1, A2, A3>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3) {
-  return new gmp_task_args_nm_4<M, A0, A1, A2, A3>
-    (m, a0, a1, a2, a3);
-}
-
-// 4 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename R>
-gmp_task_args_nm_4_ret<M, A0, A1, A2, A3, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) {
-  return new gmp_task_args_nm_4_ret<M, A0, A1, A2, A3, R>
-    (m, a0, a1, a2, a3, r);
-}
-
-// 4 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3>
-gmp_task_args_m_4<C, M, A0, A1, A2, A3>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) {
-  return new gmp_task_args_m_4<C, M, A0, A1, A2, A3>
-    (o, m, a0, a1, a2, a3);
-}
-
-// 4 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename R>
-gmp_task_args_m_4_ret<C, M, A0, A1, A2, A3, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R* r) {
-  return new gmp_task_args_m_4_ret<C, M, A0, A1, A2, A3, R>
-    (o, m, a0, a1, a2, a3, r);
-}
-
-// 5 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4>
-gmp_task_args_nm_5<M, A0, A1, A2, A3, A4>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
-  return new gmp_task_args_nm_5<M, A0, A1, A2, A3, A4>
-    (m, a0, a1, a2, a3, a4);
-}
-
-// 5 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R>
-gmp_task_args_nm_5_ret<M, A0, A1, A2, A3, A4, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) {
-  return new gmp_task_args_nm_5_ret<M, A0, A1, A2, A3, A4, R>
-    (m, a0, a1, a2, a3, a4, r);
-}
-
-// 5 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4>
-gmp_task_args_m_5<C, M, A0, A1, A2, A3, A4>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
-  return new gmp_task_args_m_5<C, M, A0, A1, A2, A3, A4>
-    (o, m, a0, a1, a2, a3, a4);
-}
-
-// 5 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename R>
-gmp_task_args_m_5_ret<C, M, A0, A1, A2, A3, A4, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R* r) {
-  return new gmp_task_args_m_5_ret<C, M, A0, A1, A2, A3, A4, R>
-    (o, m, a0, a1, a2, a3, a4, r);
-}
-
-// 6 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
-gmp_task_args_nm_6<M, A0, A1, A2, A3, A4, A5>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
-  return new gmp_task_args_nm_6<M, A0, A1, A2, A3, A4, A5>
-    (m, a0, a1, a2, a3, a4, a5);
-}
-
-// 6 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R>
-gmp_task_args_nm_6_ret<M, A0, A1, A2, A3, A4, A5, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) {
-  return new gmp_task_args_nm_6_ret<M, A0, A1, A2, A3, A4, A5, R>
-    (m, a0, a1, a2, a3, a4, a5, r);
-}
-
-// 6 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
-gmp_task_args_m_6<C, M, A0, A1, A2, A3, A4, A5>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
-  return new gmp_task_args_m_6<C, M, A0, A1, A2, A3, A4, A5>
-    (o, m, a0, a1, a2, a3, a4, a5);
-}
-
-// 6 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename R>
-gmp_task_args_m_6_ret<C, M, A0, A1, A2, A3, A4, A5, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R* r) {
-  return new gmp_task_args_m_6_ret<C, M, A0, A1, A2, A3, A4, A5, R>
-    (o, m, a0, a1, a2, a3, a4, a5, r);
-}
-
-// 7 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
-gmp_task_args_nm_7<M, A0, A1, A2, A3, A4, A5, A6>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
-  return new gmp_task_args_nm_7<M, A0, A1, A2, A3, A4, A5, A6>
-    (m, a0, a1, a2, a3, a4, a5, a6);
-}
-
-// 7 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R>
-gmp_task_args_nm_7_ret<M, A0, A1, A2, A3, A4, A5, A6, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) {
-  return new gmp_task_args_nm_7_ret<M, A0, A1, A2, A3, A4, A5, A6, R>
-    (m, a0, a1, a2, a3, a4, a5, a6, r);
-}
-
-// 7 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
-gmp_task_args_m_7<C, M, A0, A1, A2, A3, A4, A5, A6>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
-  return new gmp_task_args_m_7<C, M, A0, A1, A2, A3, A4, A5, A6>
-    (o, m, a0, a1, a2, a3, a4, a5, a6);
-}
-
-// 7 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename R>
-gmp_task_args_m_7_ret<C, M, A0, A1, A2, A3, A4, A5, A6, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R* r) {
-  return new gmp_task_args_m_7_ret<C, M, A0, A1, A2, A3, A4, A5, A6, R>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, r);
-}
-
-// 8 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
-gmp_task_args_nm_8<M, A0, A1, A2, A3, A4, A5, A6, A7>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) {
-  return new gmp_task_args_nm_8<M, A0, A1, A2, A3, A4, A5, A6, A7>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7);
-}
-
-// 8 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R>
-gmp_task_args_nm_8_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) {
-  return new gmp_task_args_nm_8_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, R>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, r);
-}
-
-// 8 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
-gmp_task_args_m_8<C, M, A0, A1, A2, A3, A4, A5, A6, A7>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) {
-  return new gmp_task_args_m_8<C, M, A0, A1, A2, A3, A4, A5, A6, A7>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7);
-}
-
-// 8 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename R>
-gmp_task_args_m_8_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R* r) {
-  return new gmp_task_args_m_8_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, R>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, r);
-}
-
-// 9 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
-gmp_task_args_nm_9<M, A0, A1, A2, A3, A4, A5, A6, A7, A8>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) {
-  return new gmp_task_args_nm_9<M, A0, A1, A2, A3, A4, A5, A6, A7, A8>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8);
-}
-
-// 9 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R>
-gmp_task_args_nm_9_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) {
-  return new gmp_task_args_nm_9_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r);
-}
-
-// 9 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
-gmp_task_args_m_9<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) {
-  return new gmp_task_args_m_9<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8);
-}
-
-// 9 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename R>
-gmp_task_args_m_9_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R* r) {
-  return new gmp_task_args_m_9_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, R>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, r);
-}
-
-// 10 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
-gmp_task_args_nm_10<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) {
-  return new gmp_task_args_nm_10<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
-}
-
-// 10 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R>
-gmp_task_args_nm_10_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) {
-  return new gmp_task_args_nm_10_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r);
-}
-
-// 10 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
-gmp_task_args_m_10<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) {
-  return new gmp_task_args_m_10<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
-}
-
-// 10 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename R>
-gmp_task_args_m_10_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R* r) {
-  return new gmp_task_args_m_10_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, R>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, r);
-}
-
-// 11 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>
-gmp_task_args_nm_11<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) {
-  return new gmp_task_args_nm_11<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
-}
-
-// 11 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R>
-gmp_task_args_nm_11_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) {
-  return new gmp_task_args_nm_11_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r);
-}
-
-// 11 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>
-gmp_task_args_m_11<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) {
-  return new gmp_task_args_m_11<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
-}
-
-// 11 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename R>
-gmp_task_args_m_11_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R* r) {
-  return new gmp_task_args_m_11_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, r);
-}
-
-// 12 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11>
-gmp_task_args_nm_12<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) {
-  return new gmp_task_args_nm_12<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
-}
-
-// 12 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R>
-gmp_task_args_nm_12_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) {
-  return new gmp_task_args_nm_12_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r);
-}
-
-// 12 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11>
-gmp_task_args_m_12<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) {
-  return new gmp_task_args_m_12<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
-}
-
-// 12 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename R>
-gmp_task_args_m_12_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R* r) {
-  return new gmp_task_args_m_12_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, r);
-}
-
-// 13 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12>
-gmp_task_args_nm_13<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) {
-  return new gmp_task_args_nm_13<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
-}
-
-// 13 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R>
-gmp_task_args_nm_13_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) {
-  return new gmp_task_args_nm_13_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r);
-}
-
-// 13 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12>
-gmp_task_args_m_13<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) {
-  return new gmp_task_args_m_13<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
-}
-
-// 13 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename R>
-gmp_task_args_m_13_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R* r) {
-  return new gmp_task_args_m_13_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, r);
-}
-
-// 14 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13>
-gmp_task_args_nm_14<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>* WrapTaskNM(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) {
-  return new gmp_task_args_nm_14<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
-}
-
-// 14 arguments --
-template<typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R>
-gmp_task_args_nm_14_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>* WrapTaskNMRet(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) {
-  return new gmp_task_args_nm_14_ret<M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>
-    (m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r);
-}
-
-// 14 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13>
-gmp_task_args_m_14<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>* WrapTask(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) {
-  return new gmp_task_args_m_14<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
-}
-
-// 14 arguments --
-template<typename C, typename M, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename R>
-gmp_task_args_m_14_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>* WrapTaskRet(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R* r) {
-  return new gmp_task_args_m_14_ret<C, M, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, R>
-    (o, m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, r);
-}
-
-class RefCountTaskWrapper : public gmp_task_args_base {
-public:
-  RefCountTaskWrapper(GMPTask* aTask, RefCounted* aRefCounted)
-    : mTask(aTask)
-    , mRefCounted(aRefCounted)
-  {}
-  virtual void Run() override {
-    mTask->Run();
-  }
-  virtual void Destroy() override {
-    mTask->Destroy();
-    gmp_task_args_base::Destroy();
-  }
-private:
-  ~RefCountTaskWrapper() {}
-
-  GMPTask* mTask;
-  RefPtr<RefCounted> mRefCounted;
-};
-
-template<typename Type, typename Method, typename... Args>
-GMPTask*
-WrapTaskRefCounted(Type* aType, Method aMethod, Args&&... args)
-{
-  GMPTask* t = WrapTask(aType, aMethod, std::forward<Args>(args)...);
-  return new RefCountTaskWrapper(t, aType);
-}
deleted file mode 100644
--- a/media/gmp-clearkey/0.1/gmp-task-utils.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2015, Mozilla Foundation and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Original author: ekr@rtfm.com
-
-#ifndef gmp_task_utils_h_
-#define gmp_task_utils_h_
-
-#include "gmp-api/gmp-platform.h"
-
-class gmp_task_args_base : public GMPTask {
-public:
-  virtual void Destroy() { delete this; }
-  virtual void Run() = 0;
-};
-
-// The generated file contains four major function templates
-// (in variants for arbitrary numbers of arguments up to 10,
-// which is why it is machine generated). The four templates
-// are:
-//
-// WrapTask(o, m, ...) -- wraps a member function m of an object ptr o
-// WrapTaskRet(o, m, ..., r) -- wraps a member function m of an object ptr o
-//                                  the function returns something that can
-//                                  be assigned to *r
-// WrapTaskNM(f, ...) -- wraps a function f
-// WrapTaskNMRet(f, ..., r) -- wraps a function f that returns something
-//                                 that can be assigned to *r
-//
-// All of these template functions return a GMPTask* which can be passed
-// to DispatchXX().
-#include "gmp-task-utils-generated.h"
-
-#endif // gmp_task_utils_h_
new file mode 100644
--- /dev/null
+++ b/media/gmp-clearkey/0.1/manifest.json.in
@@ -0,0 +1,13 @@
+{
+    "name": "clearkey",
+    "description": "ClearKey Gecko Media Plugin",
+    "version": "1",
+    "x-cdm-module-versions": "4",
+    "x-cdm-interface-versions": "8",
+    "x-cdm-host-versions": "8",
+#ifdef ENABLE_WMF
+    "x-cdm-codecs": "avc1"
+#else
+    "x-cdm-codecs": ""
+#endif
+}
\ No newline at end of file
--- a/media/gmp-clearkey/0.1/moz.build
+++ b/media/gmp-clearkey/0.1/moz.build
@@ -3,60 +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/.
 
 SharedLibrary('clearkey')
 
 FINAL_TARGET = 'dist/bin/gmp-clearkey/0.1'
 
-FINAL_TARGET_PP_FILES += ['clearkey.info.in']
+FINAL_TARGET_PP_FILES += ['manifest.json.in']
 
 UNIFIED_SOURCES += [
-    'ClearKeyAsyncShutdown.cpp',
     'ClearKeyBase64.cpp',
+    'ClearKeyCDM.cpp',
     'ClearKeyDecryptionManager.cpp',
     'ClearKeyPersistence.cpp',
     'ClearKeySession.cpp',
     'ClearKeySessionManager.cpp',
     'ClearKeyStorage.cpp',
     'ClearKeyUtils.cpp',
     'gmp-clearkey.cpp',
 ]
 
 SOURCES += [
     'openaes/oaes_lib.c',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     UNIFIED_SOURCES += [
-        'AnnexB.cpp',
         'VideoDecoder.cpp',
         'WMFH264Decoder.cpp',
     ]
 
     SOURCES += [
         'WMFUtils.cpp',
     ]
 
     OS_LIBS += [
         'mfuuid',
     ]
 
     DEFINES['ENABLE_WMF'] = True
 
+
+DEFINES['CDM_IMPLEMENTATION'] = True
+
 TEST_DIRS += [
     'gtest',
 ]
 
-
-LOCAL_INCLUDES += [
-    '/dom/media/gmp',
-]
-
 DISABLE_STL_WRAPPING = True
 DEFINES['MOZ_NO_MOZALLOC'] = True
 
 USE_LIBS += ['psshparser']
 
 # Suppress warnings in third-party code.
 if CONFIG['GNU_CXX']:
     CFLAGS += [
--- a/netwerk/base/LoadContextInfo.cpp
+++ b/netwerk/base/LoadContextInfo.cpp
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LoadContextInfo.h"
 
 #include "mozilla/dom/ToJSValue.h"
+#include "nsDocShell.h"
 #include "nsIChannel.h"
 #include "nsILoadContext.h"
 #include "nsIWebNavigation.h"
 #include "nsNetUtil.h"
 
 using namespace mozilla::dom;
 namespace mozilla {
 namespace net {
@@ -138,22 +139,27 @@ GetLoadContextInfo(nsIChannel * aChannel
 
 LoadContextInfo *
 GetLoadContextInfo(nsILoadContext *aLoadContext, bool aIsAnonymous)
 {
   if (!aLoadContext) {
     return new LoadContextInfo(aIsAnonymous, OriginAttributes());
   }
 
-  DebugOnly<bool> pb = aLoadContext->UsePrivateBrowsing();
   OriginAttributes oa;
   aLoadContext->GetOriginAttributes(oa);
   oa.StripAttributes(OriginAttributes::STRIP_ADDON_ID);
 
-  MOZ_ASSERT(pb == (oa.mPrivateBrowsingId > 0));
+#ifdef DEBUG
+  nsCOMPtr<nsIDocShellTreeItem> docShell = do_QueryInterface(aLoadContext);
+  if (!docShell || docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
+    MOZ_ASSERT(aLoadContext->UsePrivateBrowsing() == (oa.mPrivateBrowsingId > 0));
+  }
+#endif
+
   return new LoadContextInfo(aIsAnonymous, oa);
 }
 
 LoadContextInfo*
 GetLoadContextInfo(nsIDOMWindow *aWindow,
                    bool aIsAnonymous)
 {
   nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
--- a/testing/mochitest/moz.build
+++ b/testing/mochitest/moz.build
@@ -163,16 +163,19 @@ TEST_HARNESS_FILES.testing.mochitest.ice
 TEST_HARNESS_FILES.testing.mochitest.websocketprocessbridge += [
     '/testing/tools/websocketprocessbridge/websocketprocessbridge.py',
     '/testing/tools/websocketprocessbridge/websocketprocessbridge_requirements.txt',
 ]
 
 with Files("**"):
     BUG_COMPONENT = ("Testing", "Mochitest")
 
+with Files("*remote*"):
+    BUG_COMPONENT = ("Firefox for Android", "Testing")
+
 with Files("chrome/**"):
     BUG_COMPONENT = ("Testing", "Mochitest Chrome")
 
 with Files("chrome-harness.js"):
     BUG_COMPONENT = ("Testing", "Mochitest Chrome")
 
 with Files("BrowserTestUtils/**"):
     BUG_COMPONENT = ("Testing", "BrowserTest")
new file mode 100644
--- /dev/null
+++ b/testing/moz.build
@@ -0,0 +1,101 @@
+with Files("talos/**"):
+    BUG_COMPONENT = ("Testing", "Talos")
+
+with Files("talos/talos/tests/v8_7/**"):
+    BUG_COMPONENT = ("Core", "Javascript Engine")
+
+with Files("talos/talos/tests/kraken/**"):
+    BUG_COMPONENT = ("Core", "Javascript Engine")
+
+with Files("talos/talos/tests/a11y/**"):
+    BUG_COMPONENT = ("Core", "Disability Access APIs")
+
+with Files("talos/talos/tests/canvasmark/**"):
+    BUG_COMPONENT = ("Core", "Canvas: 2D")
+
+with Files("talos/talos/tests/webgl/**"):
+    BUG_COMPONENT = ("Core", "Canvas: WebGL")
+
+with Files("talos/talos/tests/dromaeo/**"):
+    BUG_COMPONENT = ("Core", "DOM")
+
+with Files("talos/talos/tests/svg*"):
+    BUG_COMPONENT = ("Core", "SVG")
+
+with Files("talos/talos/tests/scroll/**"):
+    BUG_COMPONENT = ("Core", "Graphics")
+
+with Files("talos/talos/tests/tabpaint/**"):
+    BUG_COMPONENT = ("Firefox", "Tabbed Browser")
+
+with Files("talos/talos/tests/tart/**"):
+    BUG_COMPONENT = ("Firefox", "Tabbed Browser")
+
+with Files("talos/talos/tests/tabswitch/**"):
+    BUG_COMPONENT = ("Firefox", "Tabbed Browser")
+
+with Files("talos/talos/tests/video/**"):
+    BUG_COMPONENT = ("Core", "Audio/Video: Playback")
+
+with Files("talos/talos/startup_test/sessionrestore/**"):
+    BUG_COMPONENT = ("Firefox", "Session Restore")
+
+with Files("talos/talos/startup_test/tresize/**"):
+    BUG_COMPONENT = ("Core", "XUL")
+
+with Files("tps/**"):
+    BUG_COMPONENT = ("Testing", "TPS")
+
+with Files("mozharness/**"):
+    BUG_COMPONENT = ("Release Engineering", "Mozharness")
+
+with Files("config/tooltool-manifests/**"):
+    BUG_COMPONENT = ("Release Engineering", "Mozharness")
+
+with Files("*cppunittest*"):
+    BUG_COMPONENT = ("Testing", "General")
+
+with Files("gtest/**"):
+    BUG_COMPONENT = ("Testing", "General")
+
+with Files("specialpowers/**"):
+    BUG_COMPONENT = ("Testing", "Mochitest")
+
+with Files("crashtest/**"):
+    BUG_COMPONENT = ("Testing", "Reftest")
+
+with Files("crashtest/autophone-crashtest-webrtc.list"):
+    BUG_COMPONENT = ("Testing", "Autophone")
+
+with Files("config/marionette*"):
+    BUG_COMPONENT = ("Testing", "Marionette")
+
+with Files("config/mozbase_requirements.txt"):
+    BUG_COMPONENT = ("Testing", "Mozbase")
+
+with Files("config/firefox_ui_requirements.txt"):
+    BUG_COMPONENT = ("Testing", "Firfox UI Tests")
+
+with Files("config/external-media-tests-requirements.txt"):
+    BUG_COMPONENT = ("Testing", "external-media-tests")
+
+with Files("tools/**"):
+    BUG_COMPONENT = ("Testing", "General")
+
+with Files("tools/fileid/**"):
+    BUG_COMPONENT = ("Toolkit", "Breakpad Integration")
+
+with Files("tools/iceserver/**"):
+    BUG_COMPONENT = ("Core", "WebRTC: Networking")
+
+with Files("tools/websocketprocessbridge/**"):
+    BUG_COMPONENT = ("Core", "WebRTC: Networking")
+
+with Files("tools/fileid/**"):
+    BUG_COMPONENT = ("Toolkit", "Breakpad Integration")
+
+with Files("tools/minidumpwriter/**"):
+    BUG_COMPONENT = ("Toolkit", "Breakpad Integration")
+
+with Files("remote*"):
+    BUG_COMPONENT = ("Firefox for Android", "Testing")
--- a/testing/mozharness/mozharness/mozilla/testing/testbase.py
+++ b/testing/mozharness/mozharness/mozilla/testing/testbase.py
@@ -189,30 +189,33 @@ class TestingMixin(VirtualenvMixin, Buil
         url = None
         for reference_suffix in reference_suffixes:
             if reference_url.endswith(reference_suffix):
                 url = reference_url[:-len(reference_suffix)] + suffix
                 break
 
         return url
 
-    def query_symbols_url(self):
+    def query_symbols_url(self, raise_on_failure=False):
         if self.symbols_url:
             return self.symbols_url
 
         elif self.installer_url:
             symbols_url = self.query_prefixed_build_dir_url('.crashreporter-symbols.zip')
 
             # Check if the URL exists. If not, use none to allow mozcrash to auto-check for symbols
             try:
                 if symbols_url:
                     self._urlopen(symbols_url, timeout=120)
                     self.symbols_url = symbols_url
-            except (urllib2.HTTPError, urllib2.URLError, socket.error, socket.timeout):
-                self.warning("Can't figure out symbols_url from installer_url: %s!" % self.installer_url)
+            except (urllib2.HTTPError, urllib2.URLError, socket.error, socket.timeout) as ex:
+                self.warning("Cannot open symbols url %s (installer url: %s): %s" %
+                    (symbols_url, self.installer_url, ex))
+                if raise_on_failure:
+                    raise
 
         # If no symbols URL can be determined let minidump_stackwalk query the symbols.
         # As of now this only works for Nightly and release builds.
         if not self.symbols_url:
             self.warning("No symbols_url found. Let minidump_stackwalk query for symbols.")
 
         return self.symbols_url
 
@@ -519,26 +522,28 @@ 2. running via buildbot and running the 
             return
 
         else:
             # In the case for 'ondemand', we're OK to proceed without getting a hold of the
             # symbols right this moment, however, in other cases we need to at least retry
             # before being unable to proceed (e.g. debug tests need symbols)
             self.symbols_url = self.retry(
                 action=self.query_symbols_url,
+                kwargs={'raise_on_failure': True},
                 sleeptime=20,
                 error_level=FATAL,
                 error_message="We can't proceed without downloading symbols.",
             )
             if not self.symbols_path:
                 self.symbols_path = os.path.join(dirs['abs_work_dir'], 'symbols')
 
             self.set_buildbot_property("symbols_url", self.symbols_url,
                                        write_to_file=True)
-            self.download_unpack(self.symbols_url, self.symbols_path)
+            if self.symbols_url:
+                self.download_unpack(self.symbols_url, self.symbols_path)
 
     def download_and_extract(self, extract_dirs=None, suite_categories=None):
         """
         download and extract test zip / download installer
         """
         # Swap plain http for https when we're downloading from ftp
         # See bug 957502 and friends
         from_ = "http://ftp.mozilla.org"
--- a/toolkit/components/passwordmgr/test/subtst_master_pass.html
+++ b/toolkit/components/passwordmgr/test/subtst_master_pass.html
@@ -1,12 +1,7 @@
 <h2>MP subtest</h2>
 This form triggers a MP and gets filled in.<br>
 <form>
 Username: <input type="text"     id="userfield" name="u"><br>
-Password: <input type="password" id="passfield" name="p"><br>
-<script>
-    // Only notify when we fill in the password field.
-    document.getElementById("passfield").addEventListener("input", function() {
-        parent.postMessage("filled", "*");
-    });
-</script>
+Password: <input type="password" id="passfield" name="p"
+                 oninput="parent.postMessage('filled', '*');"><br>
 </form>
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -2630,16 +2630,22 @@ TelemetryImpl::SnapshotBuiltinEvents(uin
 
 NS_IMETHODIMP
 TelemetryImpl::ClearEvents()
 {
   TelemetryEvent::ClearEvents();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+TelemetryImpl::SetEventRecordingEnabled(const nsACString& aCategory, bool aEnabled)
+{
+  TelemetryEvent::SetEventRecordingEnabled(aCategory, aEnabled);
+  return NS_OK;
+}
 
 NS_IMETHODIMP
 TelemetryImpl::FlushBatchedChildTelemetry()
 {
   TelemetryHistogram::IPCTimerFired(nullptr, nullptr);
   return NS_OK;
 }
 
--- a/toolkit/components/telemetry/TelemetryEvent.cpp
+++ b/toolkit/components/telemetry/TelemetryEvent.cpp
@@ -88,17 +88,17 @@ static_assert(kEventCount < kExpiredEven
 // If we cross this limit, we will drop any further event recording until elements
 // are removed from storage.
 const uint32_t kMaxEventRecords = 1000;
 // Maximum length of any passed value string, in UTF8 byte sequence length.
 const uint32_t kMaxValueByteLength = 80;
 // Maximum length of any string value in the extra dictionary, in UTF8 byte sequence length.
 const uint32_t kMaxExtraValueByteLength = 80;
 
-typedef nsDataHashtable<nsCStringHashKey, uint32_t> EventMapType;
+typedef nsDataHashtable<nsCStringHashKey, uint32_t> StringUintMap;
 typedef nsClassHashtable<nsCStringHashKey, nsCString> StringMap;
 
 enum class RecordEventResult {
   Ok,
   UnknownEvent,
   InvalidExtraKey,
   StorageLimitReached,
 };
@@ -244,18 +244,24 @@ TruncateToByteLength(nsCString& str, uin
 namespace {
 
 // Set to true once this global state has been initialized.
 bool gInitDone = false;
 
 bool gCanRecordBase;
 bool gCanRecordExtended;
 
-// The Name -> ID cache map.
-EventMapType gEventNameIDMap(kEventCount);
+// The EventName -> EventID cache map.
+StringUintMap gEventNameIDMap(kEventCount);
+
+// The CategoryName -> CategoryID cache map.
+StringUintMap gCategoryNameIDMap;
+
+// This tracks the IDs of the categories for which recording is enabled.
+nsTHashtable<nsUint32HashKey> gEnabledCategories;
 
 // The main event storage. Events are inserted here in recording order.
 StaticAutoPtr<nsTArray<EventRecord>> gEventRecords;
 
 } // namespace
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
@@ -266,17 +272,21 @@ namespace {
 
 bool
 CanRecordEvent(const StaticMutexAutoLock& lock, const CommonEventInfo& info)
 {
   if (!gCanRecordBase) {
     return false;
   }
 
-  return CanRecordDataset(info.dataset, gCanRecordBase, gCanRecordExtended);
+  if (!CanRecordDataset(info.dataset, gCanRecordBase, gCanRecordExtended)) {
+    return false;
+  }
+
+  return gEnabledCategories.GetEntry(info.category_offset);
 }
 
 RecordEventResult
 RecordEvent(const StaticMutexAutoLock& lock, double timestamp,
             const nsACString& category, const nsACString& method,
             const nsACString& object, const Maybe<nsCString>& value,
             const ExtraArray& extra)
 {
@@ -364,34 +374,41 @@ TelemetryEvent::InitializeGlobalState(bo
     // If this event is expired, mark it with a special event id.
     // This avoids doing expensive expiry checks at runtime.
     if (IsExpiredVersion(info.common_info.expiration_version()) ||
         IsExpiredDate(info.common_info.expiration_day)) {
       eventId = kExpiredEventId;
     }
 
     gEventNameIDMap.Put(UniqueEventName(info), eventId);
+    if (!gCategoryNameIDMap.Contains(nsDependentCString(info.common_info.category()))) {
+      gCategoryNameIDMap.Put(nsDependentCString(info.common_info.category()),
+                             info.common_info.category_offset);
+    }
   }
 
 #ifdef DEBUG
   gEventNameIDMap.MarkImmutable();
+  gCategoryNameIDMap.MarkImmutable();
 #endif
   gInitDone = true;
 }
 
 void
 TelemetryEvent::DeInitializeGlobalState()
 {
   StaticMutexAutoLock locker(gTelemetryEventsMutex);
   MOZ_ASSERT(gInitDone);
 
   gCanRecordBase = false;
   gCanRecordExtended = false;
 
   gEventNameIDMap.Clear();
+  gCategoryNameIDMap.Clear();
+  gEnabledCategories.Clear();
   gEventRecords->Clear();
   gEventRecords = nullptr;
 
   gInitDone = false;
 }
 
 void
 TelemetryEvent::SetCanRecordBase(bool b)
@@ -662,26 +679,52 @@ TelemetryEvent::ClearEvents()
 
   if (!gInitDone) {
     return;
   }
 
   gEventRecords->Clear();
 }
 
+void
+TelemetryEvent::SetEventRecordingEnabled(const nsACString& category, bool enabled)
+{
+  StaticMutexAutoLock locker(gTelemetryEventsMutex);
+
+  uint32_t categoryId;
+  if (!gCategoryNameIDMap.Get(category, &categoryId)) {
+    LogToBrowserConsole(nsIScriptError::warningFlag,
+                        NS_LITERAL_STRING("Unkown category for SetEventRecordingEnabled."));
+    return;
+  }
+
+  if (enabled) {
+    gEnabledCategories.PutEntry(categoryId);
+  } else {
+    gEnabledCategories.RemoveEntry(categoryId);
+  }
+}
+
 size_t
 TelemetryEvent::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
 {
   StaticMutexAutoLock locker(gTelemetryEventsMutex);
   size_t n = 0;
 
   n += gEventRecords->ShallowSizeOfIncludingThis(aMallocSizeOf);
   for (uint32_t i = 0; i < gEventRecords->Length(); ++i) {
     n += (*gEventRecords)[i].SizeOfExcludingThis(aMallocSizeOf);
   }
 
   n += gEventNameIDMap.ShallowSizeOfExcludingThis(aMallocSizeOf);
   for (auto iter = gEventNameIDMap.ConstIter(); !iter.Done(); iter.Next()) {
     n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   }
 
+  n += gCategoryNameIDMap.ShallowSizeOfExcludingThis(aMallocSizeOf);
+  for (auto iter = gCategoryNameIDMap.ConstIter(); !iter.Done(); iter.Next()) {
+    n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  }
+
+  n += gEnabledCategories.ShallowSizeOfExcludingThis(aMallocSizeOf);
+
   return n;
 }
--- a/toolkit/components/telemetry/TelemetryEvent.h
+++ b/toolkit/components/telemetry/TelemetryEvent.h
@@ -21,16 +21,17 @@ void DeInitializeGlobalState();
 void SetCanRecordBase(bool b);
 void SetCanRecordExtended(bool b);
 
 // JS API Endpoints.
 nsresult RecordEvent(const nsACString& aCategory, const nsACString& aMethod,
                      const nsACString& aObject, JS::HandleValue aValue,
                      JS::HandleValue aExtra, JSContext* aCx,
                      uint8_t optional_argc);
+void SetEventRecordingEnabled(const nsACString& aCategory, bool aEnabled);
 nsresult CreateSnapshots(uint32_t aDataset, bool aClear, JSContext* aCx,
                          uint8_t optional_argc, JS::MutableHandleValue aResult);
 
 // Only to be used for testing.
 void ClearEvents();
 
 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -483,16 +483,26 @@ interface nsITelemetry : nsISupports
    *               It should only contain registered extra keys.
    *
    * @throws NS_ERROR_INVALID_ARG When trying to record an unknown event.
    */
   [implicit_jscontext, optional_argc]
   void recordEvent(in ACString aCategory, in ACString aMethod, in ACString aObject, [optional] in jsval aValue, [optional] in jsval extra);
 
   /**
+   * Enable recording of events in a category.
+   * Events default to recording disabled. This allows to toggle recording for all events
+   * in the specified category.
+   *
+   * @param aCategory The category name.
+   * @param aEnabled Whether recording is enabled for events in that category.
+   */
+  void setEventRecordingEnabled(in ACString aCategory, in boolean aEnabled);
+
+  /**
    * Serializes the recorded events to a JSON-appropriate array and optionally resets them.
    * The returned structure looks like this:
    *   [
    *     // [timestamp, category, method, object, stringValue, extraValues]
    *     [43245, "category1", "method1", "object1", "string value", null],
    *     [43258, "category1", "method2", "object1", null, {"key1": "string value"}],
    *     ...
    *   ]
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
@@ -31,16 +31,57 @@ function checkEventFormat(events) {
       Assert.ok(Object.keys(extra).every(k => typeof(k) == "string"),
                 "All extra keys should be strings.");
       Assert.ok(Object.values(extra).every(v => typeof(v) == "string"),
                 "All extra values should be strings.");
     }
   }
 }
 
+add_task(function* test_recording_state() {
+  const events = [
+    ["telemetry.test", "test1", "object1"],
+    ["telemetry.test.second", "test", "object1"],
+  ];
+
+  // Both test categories should be off by default.
+  events.forEach(e => Telemetry.recordEvent(...e));
+  let snapshot = Telemetry.snapshotBuiltinEvents(OPTIN, true);
+  Assert.deepEqual(snapshot, [], "Should not have recorded any events.");
+
+  // Enable one test category and see that we record correctly.
+  Telemetry.setEventRecordingEnabled("telemetry.test", true);
+  events.forEach(e => Telemetry.recordEvent(...e));
+  snapshot = Telemetry.snapshotBuiltinEvents(OPTIN, true);
+  Assert.equal(snapshot.length, 1, "Should have recorded one event.");
+  Assert.equal(snapshot[0][1], "telemetry.test", "Should have recorded one event in telemetry.test");
+
+  // Also enable the other test category and see that we record correctly.
+  Telemetry.setEventRecordingEnabled("telemetry.test.second", true);
+  events.forEach(e => Telemetry.recordEvent(...e));
+  snapshot = Telemetry.snapshotBuiltinEvents(OPTIN, true);
+  Assert.equal(snapshot.length, 2, "Should have recorded two events.");
+  Assert.equal(snapshot[0][1], "telemetry.test", "Should have recorded one event in telemetry.test");
+  Assert.equal(snapshot[1][1], "telemetry.test.second", "Should have recorded one event in telemetry.test.second");
+
+  // Now turn of one category again and check that this works as expected.
+  Telemetry.setEventRecordingEnabled("telemetry.test", false);
+  events.forEach(e => Telemetry.recordEvent(...e));
+  snapshot = Telemetry.snapshotBuiltinEvents(OPTIN, true);
+  Assert.equal(snapshot.length, 1, "Should have recorded one event.");
+  Assert.equal(snapshot[0][1], "telemetry.test.second", "Should have recorded one event in telemetry.test.second");
+});
+
+add_task(function* recording_setup() {
+  // Make sure both test categories are enabled for the remaining tests.
+  // Otherwise their event recording won't work.
+  Telemetry.setEventRecordingEnabled("telemetry.test", true);
+  Telemetry.setEventRecordingEnabled("telemetry.test.second", true);
+});
+
 add_task(function* test_recording() {
   Telemetry.clearEvents();
 
   // Record some events.
   let expected = [
     {optout: false, event: ["telemetry.test", "test1", "object1"]},
     {optout: false, event: ["telemetry.test", "test2", "object2"]},
 
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -711,16 +711,19 @@ add_task(function* test_checkSubsessionE
     // We don't support subsessions yet on Android.
     return;
   }
 
   // Clear the events.
   Telemetry.clearEvents();
   yield TelemetryController.testReset();
 
+  // Enable recording for the test events.
+  Telemetry.setEventRecordingEnabled("telemetry.test", true);
+
   // Record some events.
   let expected = [
     ["telemetry.test", "test1", "object1", "a", null],
     ["telemetry.test", "test1", "object1", null, {key1: "value"}],
   ];
   for (let event of expected) {
     Telemetry.recordEvent(...event);
   }