Merge m-c to fx-team a=merge
authorWes Kocher <wkocher@mozilla.com>
Sun, 12 Oct 2014 21:28:12 -0700
changeset 233292 3577deeda15644cc343ccbd4c5b13dd0b7ba008c
parent 233291 58a7392bde36384eaaec30381de775e9ba6fe01e (current diff)
parent 233265 f547cf19d10415162339116376904b94241874ca (diff)
child 233293 4ac3085a4111925af888408cb2ed34c99cc061fd
child 234413 c2e81e5b109296f3ab78e0afd342f2181d242e07
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone35.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 m-c to fx-team a=merge
js/public/OldDebugAPI.h
js/src/vm/OldDebugAPI.cpp
tools/footprint/README.reports
tools/footprint/buster.cgi
tools/footprint/create_dat.awk
tools/footprint/foldelf.cpp
tools/footprint/foldelf.mk
tools/footprint/leak-gauge.html
tools/footprint/leak-gauge.pl
tools/footprint/linear-regression.awk
tools/footprint/linux-gdf.mk
tools/footprint/linux.gnuplot.in
tools/footprint/lists/100.list
tools/footprint/lists/500.list
tools/footprint/lists/static41.list
tools/footprint/thrashview.cpp
tools/footprint/thrashview.mk
tools/footprint/top100.txt
tools/footprint/watch.sh
tools/footprint/win32-gdf.mk
tools/footprint/win32.gnuplot.in
tools/footprint/wm.cpp
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -56,16 +56,17 @@ this.EventManager.prototype = {
         AccessibilityEventObserver.addListener(this);
 
         this.webProgress.addProgressListener(this,
           (Ci.nsIWebProgress.NOTIFY_STATE_ALL |
            Ci.nsIWebProgress.NOTIFY_LOCATION));
         this.addEventListener('wheel', this, true);
         this.addEventListener('scroll', this, true);
         this.addEventListener('resize', this, true);
+        this._preDialogPosition = new WeakMap();
       }
       this.present(Presentation.tabStateChanged(null, 'newtab'));
 
     } catch (x) {
       Logger.logException(x, 'Failed to start EventManager');
     }
   },
 
@@ -73,16 +74,17 @@ this.EventManager.prototype = {
   // late). It is only called when the AccessFu is disabled explicitly.
   stop: function stop() {
     if (!this._started) {
       return;
     }
     Logger.debug('EventManager.stop');
     AccessibilityEventObserver.removeListener(this);
     try {
+      this._preDialogPosition.clear();
       this.webProgress.removeProgressListener(this);
       this.removeEventListener('wheel', this, true);
       this.removeEventListener('scroll', this, true);
       this.removeEventListener('resize', this, true);
     } catch (x) {
       // contentScope is dead.
     } finally {
       this._started = false;
@@ -267,18 +269,18 @@ this.EventManager.prototype = {
       {
         let position = this.contentControl.vc.position;
         if (aEvent.accessible === aEvent.accessibleDocument ||
             (position && Utils.isInSubtree(position, aEvent.accessible))) {
           // Do not automove into the document if the virtual cursor is already
           // positioned inside it.
           break;
         }
-        this.contentControl.autoMove(
-          aEvent.accessible, { delay: 500 });
+        this._preDialogPosition.set(aEvent.accessible.DOMNode, position);
+        this.contentControl.autoMove(aEvent.accessible, { delay: 500 });
         break;
       }
       case Events.VALUE_CHANGE:
       {
         let position = this.contentControl.vc.position;
         let target = aEvent.accessible;
         if (position === target ||
             Utils.getEmbeddedControl(position) === target) {
@@ -361,17 +363,18 @@ this.EventManager.prototype = {
         return;
       }
       this._queueLiveEvent(Events.HIDE, liveRegion, isPolite);
     } else {
       let vc = Utils.getVirtualCursor(this.contentScope.content.document);
       if (vc.position &&
         (Utils.getState(vc.position).contains(States.DEFUNCT) ||
           Utils.isInSubtree(vc.position, acc))) {
-        let position = aEvent.targetPrevSibling || aEvent.targetParent;
+        let position = this._preDialogPosition.get(aEvent.accessible.DOMNode) ||
+          aEvent.targetPrevSibling || aEvent.targetParent;
         if (!position) {
           try {
             position = acc.previousSibling;
           } catch (x) {
             // Accessible is unattached from the accessible tree.
             position = acc.parent;
           }
         }
--- a/accessible/tests/mochitest/jsat/doc_content_integration.html
+++ b/accessible/tests/mochitest/jsat/doc_content_integration.html
@@ -70,19 +70,19 @@
 
   </style>
 
 </head>
 <body>
   <div>Phone status bar</div>
   <div id="windows">
     <button id="back">Back</button>
-    <div id="appframe"></div>
     <div role="dialog" id="alert" hidden>
       <h1>This is an alert!</h1>
       <p>Do you agree?</p>
-      <button onclick="hideAlert()">Yes</button>
+      <button onclick="setTimeout(hideAlert, 500)">Yes</button>
       <button onclick="hideAlert()">No</button>
     </div>
+    <div id="appframe"></div>
   </div>
   <button id="home">Home</button>
 </body>
 </html>
--- a/accessible/tests/mochitest/jsat/test_content_integration.html
+++ b/accessible/tests/mochitest/jsat/test_content_integration.html
@@ -174,43 +174,46 @@
             // Must not speak Back button as it is aria-hidden
            new ExpectedCursorChange(
              ["wow", {"string": "headingLevel","args": [1]}, "such app"])],
           [doc.defaultView.ariaShowBack],
           [ContentMessages.focusSelector('button#back', true), null],
           [ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
 
           // Open dialog in outer doc, while cursor is also in outer doc
-          [ContentMessages.simpleMoveNext,
-           new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
+          [ContentMessages.simpleMoveLast,
+           new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
           [doc.defaultView.showAlert,
             new ExpectedCursorChange(['This is an alert!',
               {'string': 'headingLevel', 'args': [1]},
               {'string': 'dialog'}])],
 
           [doc.defaultView.hideAlert,
-           new ExpectedCursorChange(["wow",
-            {"string": "headingLevel", "args": [1]}, "such app"])],
+           new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
 
           [ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
 
           // Open dialog in outer doc, while cursor is in inner frame
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(
             ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
           [doc.defaultView.showAlert, new ExpectedCursorChange(['This is an alert!',
                     {'string': 'headingLevel', 'args': [1]},
                     {'string': 'dialog'}])],
 
-          // XXX: Place cursor back where it was.
-          [doc.defaultView.hideAlert,
+          [ContentMessages.simpleMoveNext,
+            new ExpectedCursorChange(['Do you agree?'])],
+          [ContentMessages.simpleMoveNext,
+            new ExpectedCursorChange(['Yes', {'string': 'pushbutton'}])],
+          [ContentMessages.activateCurrent(),
+           new ExpectedClickAction(),
            new ExpectedCursorChange(
             ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
 
           [ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
 
           // Open dialog, then focus on something when closing
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -54,8 +54,14 @@
     </popupnotification>
 
     <popupnotification id="pointerLock-notification" hidden="true">
       <popupnotificationcontent orient="vertical" align="start">
         <separator class="thin"/>
         <label id="pointerLock-cancel" value="&pointerLock.notification.message;"/>
       </popupnotificationcontent>
     </popupnotification>
+
+#ifdef E10S_TESTING_ONLY
+    <popupnotification id="enable-e10s-notification" hidden="true">
+      <popupnotificationcontent orient="vertical"/>
+    </popupnotification>
+#endif
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -102,16 +102,21 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 #ifdef NIGHTLY_BUILD
 XPCOMUtils.defineLazyModuleGetter(this, "SignInToWebsiteUX",
                                   "resource:///modules/SignInToWebsite.jsm");
 #endif
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
                                   "resource:///modules/ContentSearch.jsm");
 
+#ifdef E10S_TESTING_ONLY
+XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
+                                  "resource://gre/modules/UpdateChannel.jsm");
+#endif
+
 XPCOMUtils.defineLazyGetter(this, "ShellService", function() {
   try {
     return Cc["@mozilla.org/browser/shell-service;1"].
            getService(Ci.nsIShellService);
   }
   catch(ex) {
     return null;
   }
@@ -2256,22 +2261,25 @@ let DefaultBrowserCheck = {
     }
   },
 };
 
 #ifdef E10S_TESTING_ONLY
 let E10SUINotification = {
   // Increase this number each time we want to roll out an
   // e10s testing period to Nightly users.
-  CURRENT_NOTICE_COUNT: 0,
+  CURRENT_NOTICE_COUNT: 1,
+  CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
+  PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
 
   checkStatus: function() {
     let skipE10sChecks = false;
     try {
-      skipE10sChecks = Services.prefs.getBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y");
+      skipE10sChecks = (UpdateChannel.get() != "nightly") ||
+                       Services.prefs.getBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y");
     } catch(e) {}
 
     if (skipE10sChecks) {
       return;
     }
 
     if (Services.appinfo.browserTabsRemoteAutostart) {
       let notice = 0;
@@ -2307,27 +2315,36 @@ let E10SUINotification = {
         url += "?utm_source=tab&utm_campaign=e10sfeedback";
 
         win.openUILinkIn(url, "tab");
         return;
       }
 
       let e10sPromptShownCount = 0;
       try {
-        e10sPromptShownCount = Services.prefs.getIntPref("browser.displayedE10SPrompt");
+        e10sPromptShownCount = Services.prefs.getIntPref(this.CURRENT_PROMPT_PREF);
       } catch(e) {}
 
+      let isHardwareAccelerated = true;
+      try {
+        let win = RecentWindow.getMostRecentBrowserWindow();
+        let winutils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+        isHardwareAccelerated = winutils.layerManagerType != "Basic";
+      } catch (e) {}
+
       if (!Services.appinfo.inSafeMode &&
           !Services.appinfo.accessibilityEnabled &&
           !Services.appinfo.keyboardMayHaveIME &&
+          isHardwareAccelerated &&
           e10sPromptShownCount < 5) {
         Services.tm.mainThread.dispatch(() => {
           try {
             this._showE10SPrompt();
-            Services.prefs.setIntPref("browser.displayedE10SPrompt", e10sPromptShownCount + 1);
+            Services.prefs.setIntPref(this.CURRENT_PROMPT_PREF, e10sPromptShownCount + 1);
+            Services.prefs.clearUserPref(this.PREVIOUS_PROMPT_PREF);
           } catch (ex) {
             Cu.reportError("Failed to show e10s prompt: " + ex);
           }
         }, Ci.nsIThread.DISPATCH_NORMAL);
       }
     }
   },
 
@@ -2364,17 +2381,17 @@ let E10SUINotification = {
 
   _showE10SPrompt: function BG__showE10SPrompt() {
     let win = RecentWindow.getMostRecentBrowserWindow();
     if (!win)
       return;
 
     let browser = win.gBrowser.selectedBrowser;
 
-    let promptMessage = "Would you like to help us test multiprocess Nightly (e10s)? You can also enable e10s in Nightly preferences.";
+    let promptMessage = "Would you like to help us test multiprocess Nightly (e10s)? You can also enable e10s in Nightly preferences. Notable fixes:";
     let mainAction = {
       label: "Enable and Restart",
       accessKey: "E",
       callback: function () {
         Services.prefs.setBoolPref("browser.tabs.remote.autostart", true);
         Services.prefs.setBoolPref("browser.enabledE10SFromPrompt", true);
         // Restart the app
         let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
@@ -2384,27 +2401,41 @@ let E10SUINotification = {
         Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart);
       }
     };
     let secondaryActions = [
       {
         label: "No thanks",
         accessKey: "N",
         callback: function () {
-          Services.prefs.setIntPref("browser.displayedE10SPrompt", 5);
+          Services.prefs.setIntPref(E10SUINotification.CURRENT_PROMPT_PREF, 5);
         }
       }
     ];
     let options = {
       popupIconURL: "chrome://browser/skin/e10s-64@2x.png",
       learnMoreURL: "https://wiki.mozilla.org/Electrolysis",
       persistWhileVisible: true
     };
 
-    win.PopupNotifications.show(browser, "enable_e10s", promptMessage, null, mainAction, secondaryActions, options);
+    win.PopupNotifications.show(browser, "enable-e10s", promptMessage, null, mainAction, secondaryActions, options);
+
+    let highlights = [
+      "Less crashing!",
+      "Improved add-on compatibility and DevTools",
+      "PDF.js, Web Console, Spellchecking, WebRTC now work"
+    ];
+
+    let doorhangerExtraContent = win.document.getElementById("enable-e10s-notification")
+                                             .querySelector("popupnotificationcontent");
+    for (let highlight of highlights) {
+      let highlightLabel = win.document.createElement("label");
+      highlightLabel.setAttribute("value", highlight);
+      doorhangerExtraContent.appendChild(highlightLabel);
+    }
   },
 
   _warnedAboutAccessibility: false,
 
   _showE10sAccessibilityWarning: function() {
     Services.prefs.setBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y", true);
 
     if (this._warnedAboutAccessibility) {
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsScriptSecurityManager.h"
 
 #include "mozilla/ArrayUtils.h"
 
-#include "js/OldDebugAPI.h"
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 #include "nsIAppsService.h"
 #include "nsILoadContext.h"
 #include "nsIServiceManager.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsIURL.h"
--- a/content/base/src/EventSource.cpp
+++ b/content/base/src/EventSource.cpp
@@ -8,17 +8,16 @@
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/EventSourceBinding.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/ScriptSettings.h"
 
-#include "js/OldDebugAPI.h"
 #include "nsNetUtil.h"
 #include "nsMimeTypes.h"
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsPresContext.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIStringBundle.h"
 #include "nsIConsoleService.h"
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebSocket.h"
 #include "mozilla/dom/WebSocketBinding.h"
 #include "mozilla/net/WebSocketChannel.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/net/WebSocketChannel.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "nsIScriptGlobalObject.h"
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -16,17 +16,16 @@
 #include "harfbuzz/hb.h"
 #include "imgICache.h"
 #include "imgIContainer.h"
 #include "imgINotificationObserver.h"
 #include "imgLoader.h"
 #include "imgRequestProxy.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "js/Value.h"
 #include "Layers.h"
 #include "MediaDecoder.h"
 // nsNPAPIPluginInstance must be included before nsIDocument.h, which is included in mozAutoDocUpdate.h.
 #include "nsNPAPIPluginInstance.h"
 #include "mozAutoDocUpdate.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
--- a/content/html/content/public/HTMLMediaElement.h
+++ b/content/html/content/public/HTMLMediaElement.h
@@ -540,16 +540,21 @@ public:
   mozilla::dom::EventHandlerNonNull* GetOnencrypted();
   void SetOnencrypted(mozilla::dom::EventHandlerNonNull* listener);
 
   void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
                          const nsAString& aInitDataType);
 
 
   bool IsEventAttributeName(nsIAtom* aName) MOZ_OVERRIDE;
+
+  // Returns the principal of the "top level" document; the origin displayed
+  // in the URL bar of the browser window.
+  already_AddRefed<nsIPrincipal> GetTopLevelPrincipal();
+
 #endif // MOZ_EME
 
   bool MozAutoplayEnabled() const
   {
     return mAutoplayEnabled;
   }
 
   already_AddRefed<DOMMediaStream> MozCaptureStream(ErrorResult& aRv);
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -3402,16 +3402,21 @@ void HTMLMediaElement::NotifyDecoderPrin
   mDecoder->UpdateSameOriginStatus(
     !principal ||
     (NS_SUCCEEDED(NodePrincipal()->Subsumes(principal, &subsumes)) && subsumes));
 
   for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
     OutputMediaStream* ms = &mOutputStreams[i];
     ms->mStream->CombineWithPrincipal(principal);
   }
+#ifdef MOZ_EME
+  if (mMediaKeys && NS_FAILED(mMediaKeys->CheckPrincipals())) {
+    mMediaKeys->Shutdown();
+  }
+#endif
 }
 
 void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
 {
   mMediaSize = size;
 }
 
 void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendEvents)
@@ -4003,26 +4008,44 @@ HTMLMediaElement::SetMediaKeys(mozilla::
                                ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> global =
     do_QueryInterface(OwnerDoc()->GetInnerWindow());
   if (!global) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
-  // TODO: Need to shutdown existing MediaKeys instance? bug 1016709.
   nsRefPtr<Promise> promise = Promise::Create(global, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
-  if (mMediaKeys != aMediaKeys) {
-    mMediaKeys = aMediaKeys;
-  }
-  if (mDecoder) {
-    mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
+  if (mMediaKeys == aMediaKeys) {
+    promise->MaybeResolve(JS::UndefinedHandleValue);
+    return promise.forget();
+  }
+  if (aMediaKeys && aMediaKeys->IsBoundToMediaElement()) {
+    promise->MaybeReject(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
+    return promise.forget();
+  }
+  if (mMediaKeys) {
+    // Existing MediaKeys object. Shut it down.
+    mMediaKeys->Shutdown();
+    mMediaKeys = nullptr;
+  }
+  
+  mMediaKeys = aMediaKeys;
+  if (mMediaKeys) {
+    if (NS_FAILED(mMediaKeys->Bind(this))) {
+      promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+      mMediaKeys = nullptr;
+      return promise.forget();
+    }
+    if (mDecoder) {
+      mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
+    }
   }
   promise->MaybeResolve(JS::UndefinedHandleValue);
   return promise.forget();
 }
 
 MediaWaitingFor
 HTMLMediaElement::WaitingFor() const
 {
@@ -4058,16 +4081,38 @@ HTMLMediaElement::DispatchEncrypted(cons
 }
 
 bool
 HTMLMediaElement::IsEventAttributeName(nsIAtom* aName)
 {
   return aName == nsGkAtoms::onencrypted ||
          nsGenericHTMLElement::IsEventAttributeName(aName);
 }
+
+already_AddRefed<nsIPrincipal>
+HTMLMediaElement::GetTopLevelPrincipal()
+{
+  nsRefPtr<nsIPrincipal> principal;
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(OwnerDoc()->GetParentObject());
+  nsCOMPtr<nsIDOMWindow> topWindow;
+  if (!window) {
+    return nullptr;
+  }
+  window->GetTop(getter_AddRefs(topWindow));
+  nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow);
+  if (!top) {
+    return nullptr;
+  }
+  nsIDocument* doc = top->GetExtantDoc();
+  if (!doc) {
+    return nullptr;
+  }
+  principal = doc->NodePrincipal();
+  return principal.forget();
+}
 #endif // MOZ_EME
 
 NS_IMETHODIMP HTMLMediaElement::WindowVolumeChanged()
 {
   SetVolumeInternal();
   return NS_OK;
 }
 
--- a/content/media/FileBlockCache.cpp
+++ b/content/media/FileBlockCache.cpp
@@ -137,22 +137,22 @@ nsresult FileBlockCache::ReadFromFile(in
                                       uint8_t* aDest,
                                       int32_t aBytesToRead,
                                       int32_t& aBytesRead)
 {
   mFileMonitor.AssertCurrentThreadOwns();
 
   nsresult res = Seek(aOffset);
   if (NS_FAILED(res)) return res;
-  
+
   aBytesRead = PR_Read(mFD, aDest, aBytesToRead);
   if (aBytesRead <= 0)
     return NS_ERROR_FAILURE;
   mFDCurrentPos += aBytesRead;
-  
+
   return NS_OK;
 }
 
 nsresult FileBlockCache::WriteBlockToFile(int32_t aBlockIndex,
                                           const uint8_t* aBlockData)
 {
   mFileMonitor.AssertCurrentThreadOwns();
 
@@ -322,17 +322,17 @@ nsresult FileBlockCache::MoveBlock(int32
     // Only add another entry to the change index list if we don't already
     // have one for this block. We won't have an entry when either there's
     // no pending change for this block, or if there is a pending change for
     // this block and we're in the process of writing it (we've popped the
     // block's index out of mChangeIndexList in Run() but not finished writing
     // the block to file yet.
     mChangeIndexList.PushBack(aDestBlockIndex);
   }
-  
+
   // If the source block hasn't yet been written to file then the dest block
   // simply contains that same write. Resolve this as a write instead.
   if (sourceBlock && sourceBlock->IsWrite()) {
     mBlockChanges[aDestBlockIndex] = new BlockChange(sourceBlock->mData.get());
   } else {
     mBlockChanges[aDestBlockIndex] = new BlockChange(sourceIndex);
   }
 
--- a/content/media/FileBlockCache.h
+++ b/content/media/FileBlockCache.h
@@ -16,17 +16,17 @@
 
 struct PRFileDesc;
 
 namespace mozilla {
 
 // Manages file I/O for the media cache. Data comes in over the network
 // via callbacks on the main thread, however we don't want to write the
 // incoming data to the media cache on the main thread, as this could block
-// causing UI jank. 
+// causing UI jank.
 //
 // So FileBlockCache provides an abstraction for a temporary file accessible
 // as an array of blocks, which supports a block move operation, and
 // allows synchronous reading and writing from any thread, with writes being
 // buffered so as not to block.
 //
 // Writes and cache block moves (which require reading) are deferred to
 // their own non-main thread. This object also ensures that data which has
--- a/content/media/MediaCache.h
+++ b/content/media/MediaCache.h
@@ -26,17 +26,17 @@ class ReentrantMonitorAutoEnter;
  * for pausing, seeking, etc. But we are primarily interested
  * in transporting media data using HTTP over the Internet, which has
  * high latency to open a connection, requires a new connection for every
  * seek, may not even support seeking on some connections (especially
  * live streams), and uses a push model --- data comes from the server
  * and you don't have much control over the rate. Also, transferring data
  * over the Internet can be slow and/or unpredictable, so we want to read
  * ahead to buffer and cache as much data as possible.
- * 
+ *
  * The job of the media cache is to resolve this impedance mismatch.
  * The media cache reads data from Necko channels into file-backed storage,
  * and offers a random-access file-like API to the stream data
  * (MediaCacheStream). Along the way it solves several problems:
  * -- The cache intelligently reads ahead to prefetch data that may be
  * needed in the future
  * -- The size of the cache is bounded so that we don't fill up
  * storage with read-ahead data
@@ -51,35 +51,35 @@ class ReentrantMonitorAutoEnter;
  * (seeking to EOF and then seeking back to the previous offset does not
  * trigger any Necko activity)
  * -- The cache also handles the case where the server does not support
  * seeking
  * -- Necko can only send data to the main thread, but MediaCacheStream
  * can distribute data to any thread
  * -- The cache exposes APIs so clients can detect what data is
  * currently held
- * 
+ *
  * Note that although HTTP is the most important transport and we only
  * support transport-level seeking via HTTP byte-ranges, the media cache
  * works with any kind of Necko channels and provides random access to
  * cached data even for, e.g., FTP streams.
- * 
+ *
  * The media cache is not persistent. It does not currently allow
  * data from one load to be used by other loads, either within the same
  * browser session or across browser sessions. The media cache file
  * is marked "delete on close" so it will automatically disappear in the
  * event of a browser crash or shutdown.
- * 
+ *
  * The media cache is block-based. Streams are divided into blocks of a
  * fixed size (currently 4K) and we cache blocks. A single cache contains
  * blocks for all streams.
- * 
+ *
  * The cache size is controlled by the media.cache_size preference
  * (which is in KB). The default size is 500MB.
- * 
+ *
  * The replacement policy predicts a "time of next use" for each block
  * in the cache. When we need to free a block, the block with the latest
  * "time of next use" will be evicted. Blocks are divided into
  * different classes, each class having its own predictor:
  * FREE_BLOCK: these blocks are effectively infinitely far in the future;
  * a free block will always be chosen for replacement before other classes
  * of blocks.
  * METADATA_BLOCK: these are blocks that contain data that has been read
@@ -103,87 +103,87 @@ class ReentrantMonitorAutoEnter;
  * read point by the decoder's estimate of its playback rate in bytes
  * per second. This ensures that the blocks farthest ahead are considered
  * least valuable.
  * For efficient prediction of the "latest time of next use", we maintain
  * linked lists of blocks in each class, ordering blocks by time of
  * next use. READAHEAD_BLOCKS have one linked list per stream, since their
  * time of next use depends on stream parameters, but the other lists
  * are global.
- * 
+ *
  * A block containing a current decoder read point can contain data
  * both behind and ahead of the read point. It will be classified as a
  * PLAYED_BLOCK but we will give it special treatment so it is never
  * evicted --- it actually contains the highest-priority readahead data
  * as well as played data.
- * 
+ *
  * "Time of next use" estimates are also used for flow control. When
  * reading ahead we can predict the time of next use for the data that
  * will be read. If the predicted time of next use is later then the
  * prediction for all currently cached blocks, and the cache is full, then
  * we should suspend reading from the Necko channel.
- * 
+ *
  * Unfortunately suspending the Necko channel can't immediately stop the
  * flow of data from the server. First our desire to suspend has to be
  * transmitted to the server (in practice, Necko stops reading from the
  * socket, which causes the kernel to shrink its advertised TCP receive
  * window size to zero). Then the server can stop sending the data, but
  * we will receive data roughly corresponding to the product of the link
  * bandwidth multiplied by the round-trip latency. We deal with this by
  * letting the cache overflow temporarily and then trimming it back by
  * moving overflowing blocks back into the body of the cache, replacing
  * less valuable blocks as they become available. We try to avoid simply
  * discarding overflowing readahead data.
- * 
+ *
  * All changes to the actual contents of the cache happen on the main
  * thread, since that's where Necko's notifications happen.
  *
  * The media cache maintains at most one Necko channel for each stream.
  * (In the future it might be advantageous to relax this, e.g. so that a
  * seek to near the end of the file can happen without disturbing
  * the loading of data from the beginning of the file.) The Necko channel
  * is managed through ChannelMediaResource; MediaCache does not
  * depend on Necko directly.
- * 
+ *
  * Every time something changes that might affect whether we want to
  * read from a Necko channel, or whether we want to seek on the Necko
  * channel --- such as data arriving or data being consumed by the
  * decoder --- we asynchronously trigger MediaCache::Update on the main
  * thread. That method implements most cache policy. It evaluates for
  * each stream whether we want to suspend or resume the stream and what
  * offset we should seek to, if any. It is also responsible for trimming
  * back the cache size to its desired limit by moving overflowing blocks
  * into the main part of the cache.
- * 
+ *
  * Streams can be opened in non-seekable mode. In non-seekable mode,
  * the cache will only call ChannelMediaResource::CacheClientSeek with
  * a 0 offset. The cache tries hard not to discard readahead data
  * for non-seekable streams, since that could trigger a potentially
  * disastrous re-read of the entire stream. It's up to cache clients
  * to try to avoid requesting seeks on such streams.
- * 
+ *
  * MediaCache has a single internal monitor for all synchronization.
  * This is treated as the lowest level monitor in the media code. So,
  * we must not acquire any MediaDecoder locks or MediaResource locks
  * while holding the MediaCache lock. But it's OK to hold those locks
  * and then get the MediaCache lock.
- * 
+ *
  * MediaCache associates a principal with each stream. CacheClientSeek
  * can trigger new HTTP requests; due to redirects to other domains,
  * each HTTP load can return data with a different principal. This
  * principal must be passed to NotifyDataReceived, and MediaCache
  * will detect when different principals are associated with data in the
  * same stream, and replace them with a null principal.
  */
 class MediaCache;
 
 /**
  * If the cache fails to initialize then Init will fail, so nonstatic
  * methods of this class can assume gMediaCache is non-null.
- * 
+ *
  * This class can be directly embedded as a value.
  */
 class MediaCacheStream {
 public:
   enum {
     // This needs to be a power of two
     BLOCK_SIZE = 32768
   };
@@ -352,17 +352,17 @@ public:
 private:
   friend class MediaCache;
 
   /**
    * A doubly-linked list of blocks. Add/Remove/Get methods are all
    * constant time. We declare this here so that a stream can contain a
    * BlockList of its read-ahead blocks. Blocks are referred to by index
    * into the MediaCache::mIndex array.
-   * 
+   *
    * Blocks can belong to more than one list at the same time, because
    * the next/prev pointers are not stored in the block.
    */
   class BlockList {
   public:
     BlockList() : mFirstBlock(-1), mCount(0) {}
     ~BlockList() {
       NS_ASSERTION(mFirstBlock == -1 && mCount == 0,
--- a/content/media/VideoUtils.cpp
+++ b/content/media/VideoUtils.cpp
@@ -6,17 +6,19 @@
 #include "MediaResource.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsMathUtils.h"
 #include "nsSize.h"
 #include "VorbisUtils.h"
 #include "ImageContainer.h"
 #include "SharedThreadPool.h"
 #include "mozilla/Preferences.h"
-
+#include "mozilla/Base64.h"
+#include "nsIRandomGenerator.h"
+#include "nsIServiceManager.h"
 #include <stdint.h>
 
 namespace mozilla {
 
 using layers::PlanarYCbCrImage;
 
 // Converts from number of audio frames to microseconds, given the specified
 // audio rate.
@@ -225,9 +227,47 @@ ExtractH264CodecDetails(const nsAString&
   NS_ENSURE_SUCCESS(rv, false);
 
   aLevel = PromiseFlatString(Substring(aCodec, 9, 2)).ToInteger(&rv, 16);
   NS_ENSURE_SUCCESS(rv, false);
 
   return true;
 }
 
+nsresult
+GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength)
+{
+  nsresult rv;
+  nsCOMPtr<nsIRandomGenerator> rg =
+    do_GetService("@mozilla.org/security/random-generator;1", &rv);
+  if (NS_FAILED(rv)) return rv;
+
+  // For each three bytes of random data we will get four bytes of
+  // ASCII. Request a bit more to be safe and truncate to the length
+  // we want at the end.
+  const uint32_t requiredBytesLength =
+    static_cast<uint32_t>((aLength + 1) / 4 * 3);
+
+  uint8_t* buffer;
+  rv = rg->GenerateRandomBytes(requiredBytesLength, &buffer);
+  if (NS_FAILED(rv)) return rv;
+
+  nsAutoCString temp;
+  nsDependentCSubstring randomData(reinterpret_cast<const char*>(buffer),
+                                   requiredBytesLength);
+  rv = Base64Encode(randomData, temp);
+  NS_Free(buffer);
+  buffer = nullptr;
+  if (NS_FAILED (rv)) return rv;
+
+  temp.Truncate(aLength);
+
+  // Base64 characters are alphanumeric (a-zA-Z0-9) and '+' and '/', so we need
+  // to replace illegal characters -- notably '/'
+  temp.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
+
+  aOutSalt = temp;
+
+  return NS_OK;
+}
+
+
 } // end namespace mozilla
--- a/content/media/VideoUtils.h
+++ b/content/media/VideoUtils.h
@@ -252,11 +252,17 @@ enum H264_LEVEL {
 // See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html
 // for more details.
 // Returns false on failure.
 bool
 ExtractH264CodecDetails(const nsAString& aCodecs,
                         int16_t& aProfile,
                         int16_t& aLevel);
 
+// Use a cryptographic quality PRNG to generate raw random bytes
+// and convert that to a base64 string suitable for use as a file or URL
+// path. This is based on code from nsExternalAppHandler::SetUpTempFile.
+nsresult
+GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength);
+
 } // end namespace mozilla
 
 #endif
--- a/content/media/android/AndroidMediaReader.cpp
+++ b/content/media/android/AndroidMediaReader.cpp
@@ -237,17 +237,17 @@ bool AndroidMediaReader::DecodeVideoFram
                             pos,
                             frame.mTimeUs,
                             1, // We don't know the duration yet.
                             b,
                             frame.mKeyFrame,
                             -1,
                             picture);
     }
- 
+
     if (!v) {
       return false;
     }
     parsed++;
     decoded++;
     NS_ASSERTION(decoded <= parsed, "Expect to decode fewer frames than parsed in AndroidMedia...");
 
     // Since MPAPI doesn't give us the end time of frames, we keep one frame
--- a/content/media/android/AndroidMediaResourceServer.cpp
+++ b/content/media/android/AndroidMediaResourceServer.cpp
@@ -433,56 +433,29 @@ AndroidMediaResourceServer::Stop()
 
 nsresult
 AndroidMediaResourceServer::AppendRandomPath(nsCString& aUrl)
 {
   // Use a cryptographic quality PRNG to generate raw random bytes
   // and convert that to a base64 string for use as an URL path. This
   // is based on code from nsExternalAppHandler::SetUpTempFile.
   nsresult rv;
-  nsCOMPtr<nsIRandomGenerator> rg =
-    do_GetService("@mozilla.org/security/random-generator;1", &rv);
-  if (NS_FAILED(rv)) return rv;
-
-  // For each three bytes of random data we will get four bytes of
-  // ASCII. Request a bit more to be safe and truncate to the length
-  // we want at the end.
-  const uint32_t wantedFileNameLength = 16;
-  const uint32_t requiredBytesLength =
-    static_cast<uint32_t>((wantedFileNameLength + 1) / 4 * 3);
-
-  uint8_t* buffer;
-  rv = rg->GenerateRandomBytes(requiredBytesLength, &buffer);
+  nsAutoCString salt;
+  rv = GenerateRandomPathName(salt, 16);
   if (NS_FAILED(rv)) return rv;
-
-  nsAutoCString tempLeafName;
-  nsDependentCSubstring randomData(reinterpret_cast<const char*>(buffer),
-                                   requiredBytesLength);
-  rv = Base64Encode(randomData, tempLeafName);
-  NS_Free(buffer);
-  buffer = nullptr;
-  if (NS_FAILED (rv)) return rv;
-
-  tempLeafName.Truncate(wantedFileNameLength);
-
-  // Base64 characters are alphanumeric (a-zA-Z0-9) and '+' and '/', so we need
-  // to replace illegal characters -- notably '/'
-  tempLeafName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
-
   aUrl += "/";
-  aUrl += tempLeafName;
-
+  aUrl += salt;
   return NS_OK;
 }
 
 nsresult
 AndroidMediaResourceServer::AddResource(mozilla::MediaResource* aResource, nsCString& aUrl)
 {
   nsCString url = GetURLPrefix();
-  nsresult rv = AppendRandomPath(url);
+  nsresult rv = GenerateRandomPathName(url, 16);
   if (NS_FAILED (rv)) return rv;
 
   {
     MutexAutoLock lock(mMutex);
 
     // Adding a resource URL that already exists is considered an error.
     if (mResources.find(aUrl) != mResources.end()) return NS_ERROR_FAILURE;
     mResources[url] = aResource;
--- a/content/media/eme/CDMProxy.cpp
+++ b/content/media/eme/CDMProxy.cpp
@@ -31,88 +31,115 @@ CDMProxy::CDMProxy(dom::MediaKeys* aKeys
 }
 
 CDMProxy::~CDMProxy()
 {
   MOZ_COUNT_DTOR(CDMProxy);
 }
 
 void
-CDMProxy::Init(PromiseId aPromiseId)
+CDMProxy::Init(PromiseId aPromiseId,
+               const nsAString& aOrigin,
+               const nsAString& aTopLevelOrigin,
+               bool aInPrivateBrowsing)
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
 
-  nsresult rv = mKeys->GetOrigin(mOrigin);
-  if (NS_FAILED(rv)) {
-    RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  EME_LOG("Creating CDMProxy for origin='%s'",
-          NS_ConvertUTF16toUTF8(GetOrigin()).get());
+  EME_LOG("CDMProxy::Init (%s, %s) %s",
+          NS_ConvertUTF16toUTF8(aOrigin).get(),
+          NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
+          (aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
 
   if (!mGMPThread) {
     nsCOMPtr<mozIGeckoMediaPluginService> mps =
       do_GetService("@mozilla.org/gecko-media-plugin-service;1");
     if (!mps) {
       RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
       return;
     }
     mps->GetThread(getter_AddRefs(mGMPThread));
     if (!mGMPThread) {
       RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
       return;
     }
   }
-
-  nsRefPtr<nsIRunnable> task(NS_NewRunnableMethodWithArg<uint32_t>(this, &CDMProxy::gmp_Init, aPromiseId));
+  nsAutoPtr<InitData> data(new InitData());
+  data->mPromiseId = aPromiseId;
+  data->mOrigin = aOrigin;
+  data->mTopLevelOrigin = aTopLevelOrigin;
+  data->mInPrivateBrowsing = aInPrivateBrowsing;
+  nsRefPtr<nsIRunnable> task(
+    NS_NewRunnableMethodWithArg<nsAutoPtr<InitData>>(this,
+                                                     &CDMProxy::gmp_Init,
+                                                     data));
   mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
 }
 
 #ifdef DEBUG
 bool
 CDMProxy::IsOnGMPThread()
 {
   return NS_GetCurrentThread() == mGMPThread;
 }
 #endif
 
 void
-CDMProxy::gmp_Init(uint32_t aPromiseId)
+CDMProxy::gmp_Init(nsAutoPtr<InitData> aData)
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   nsCOMPtr<mozIGeckoMediaPluginService> mps =
     do_GetService("@mozilla.org/gecko-media-plugin-service;1");
   if (!mps) {
-    RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+    RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
+  nsresult rv = mps->GetNodeId(aData->mOrigin,
+                               aData->mTopLevelOrigin,
+                               aData->mInPrivateBrowsing,
+                               mNodeId);
+  MOZ_ASSERT(!GetNodeId().IsEmpty());
+  if (NS_FAILED(rv)) {
+    RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  EME_LOG("CDMProxy::gmp_Init (%s, %s) %s NodeId=%s",
+          NS_ConvertUTF16toUTF8(aData->mOrigin).get(),
+          NS_ConvertUTF16toUTF8(aData->mTopLevelOrigin).get(),
+          (aData->mInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"),
+          GetNodeId().get());
+
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
-  nsresult rv = mps->GetGMPDecryptor(&tags, GetOrigin(), &mCDM);
+  rv = mps->GetGMPDecryptor(&tags, GetNodeId(), &mCDM);
   if (NS_FAILED(rv) || !mCDM) {
-    RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
+    RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
   } else {
     mCallback = new CDMCallbackProxy(this);
     mCDM->Init(mCallback);
-    nsRefPtr<nsIRunnable> task(NS_NewRunnableMethodWithArg<uint32_t>(this, &CDMProxy::OnCDMCreated, aPromiseId));
+    nsRefPtr<nsIRunnable> task(
+      NS_NewRunnableMethodWithArg<uint32_t>(this,
+                                            &CDMProxy::OnCDMCreated,
+                                            aData->mPromiseId));
     NS_DispatchToMainThread(task);
   }
 }
 
 void
 CDMProxy::OnCDMCreated(uint32_t aPromiseId)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mKeys.IsNull()) {
     return;
   }
-  mKeys->OnCDMCreated(aPromiseId);
+  MOZ_ASSERT(!GetNodeId().IsEmpty());
+  mKeys->OnCDMCreated(aPromiseId, GetNodeId());
 }
 
 void
 CDMProxy::CreateSession(dom::SessionType aSessionType,
                         PromiseId aPromiseId,
                         const nsAString& aInitDataType,
                         nsTArray<uint8_t>& aInitData)
 {
@@ -351,20 +378,20 @@ CDMProxy::ResolvePromise(PromiseId aId)
     nsRefPtr<nsIRunnable> task;
     task = NS_NewRunnableMethodWithArg<PromiseId>(this,
                                                   &CDMProxy::ResolvePromise,
                                                   aId);
     NS_DispatchToMainThread(task);
   }
 }
 
-const nsAString&
-CDMProxy::GetOrigin() const
+const nsCString&
+CDMProxy::GetNodeId() const
 {
-  return mOrigin;
+  return mNodeId;
 }
 
 void
 CDMProxy::OnResolveNewSessionPromise(uint32_t aPromiseId,
                                      const nsAString& aSessionId)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mKeys.IsNull()) {
--- a/content/media/eme/CDMProxy.h
+++ b/content/media/eme/CDMProxy.h
@@ -43,17 +43,20 @@ public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMProxy)
 
   // Main thread only.
   CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem);
 
   // Main thread only.
   // Loads the CDM corresponding to mKeySystem.
   // Calls MediaKeys::OnCDMCreated() when the CDM is created.
-  void Init(PromiseId aPromiseId);
+  void Init(PromiseId aPromiseId,
+            const nsAString& aOrigin,
+            const nsAString& aTopLevelOrigin,
+            bool aInPrivateBrowsing);
 
   // Main thread only.
   // Uses the CDM to create a key session.
   // Calls MediaKeys::OnSessionActivated() when session is created.
   // Assumes ownership of (Move()s) aInitData's contents.
   void CreateSession(dom::SessionType aSessionType,
                      PromiseId aPromiseId,
                      const nsAString& aInitDataType,
@@ -97,17 +100,17 @@ public:
   // processed the request.
   void RemoveSession(const nsAString& aSessionId,
                      PromiseId aPromiseId);
 
   // Main thread only.
   void Shutdown();
 
   // Threadsafe.
-  const nsAString& GetOrigin() const;
+  const nsCString& GetNodeId() const;
 
   // Main thread only.
   void OnResolveNewSessionPromise(uint32_t aPromiseId,
                                   const nsAString& aSessionId);
 
   // Main thread only.
   void OnResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccess);
 
@@ -160,18 +163,25 @@ public:
   CDMCaps& Capabilites();
 
 #ifdef DEBUG
   bool IsOnGMPThread();
 #endif
 
 private:
 
+  struct InitData {
+    uint32_t mPromiseId;
+    nsAutoString mOrigin;
+    nsAutoString mTopLevelOrigin;
+    bool mInPrivateBrowsing;
+  };
+
   // GMP thread only.
-  void gmp_Init(uint32_t aPromiseId);
+  void gmp_Init(nsAutoPtr<InitData> aData);
 
   // GMP thread only.
   void gmp_Shutdown();
 
   // Main thread only.
   void OnCDMCreated(uint32_t aPromiseId);
 
   struct CreateSessionData {
@@ -281,17 +291,17 @@ private:
   MainThreadOnlyRawPtr<dom::MediaKeys> mKeys;
 
   const nsAutoString mKeySystem;
 
   // Gecko Media Plugin thread. All interactions with the out-of-process
   // EME plugin must come from this thread.
   nsRefPtr<nsIThread> mGMPThread;
 
-  nsAutoString mOrigin;
+  nsCString mNodeId;
 
   GMPDecryptorProxy* mCDM;
   CDMCaps mCapabilites;
   nsAutoPtr<CDMCallbackProxy> mCallback;
 
   // Decryption jobs sent to CDM, awaiting result.
   // GMP thread only.
   nsTArray<nsAutoPtr<DecryptJob>> mDecryptionJobs;
--- a/content/media/eme/MediaKeys.cpp
+++ b/content/media/eme/MediaKeys.cpp
@@ -20,16 +20,17 @@
 #include "mozilla/WindowsVersion.h"
 #endif
 
 namespace mozilla {
 
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeys,
+                                      mElement,
                                       mParent,
                                       mKeySessions,
                                       mPromises,
                                       mPendingSessions);
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeys)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeys)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeys)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@@ -219,58 +220,124 @@ MediaKeys::ResolvePromise(PromiseId aId)
 already_AddRefed<Promise>
 MediaKeys::Create(const GlobalObject& aGlobal,
                   const nsAString& aKeySystem,
                   ErrorResult& aRv)
 {
   // CDMProxy keeps MediaKeys alive until it resolves the promise and thus
   // returns the MediaKeys object to JS.
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
-  if (!window) {
+  if (!window || !window->GetExtantDoc()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<MediaKeys> keys = new MediaKeys(window, aKeySystem);
-  nsRefPtr<Promise> promise(keys->MakePromise(aRv));
+  return keys->Init(aRv);
+}
+
+already_AddRefed<Promise>
+MediaKeys::Init(ErrorResult& aRv)
+{
+  nsRefPtr<Promise> promise(MakePromise(aRv));
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  if (!IsSupportedKeySystem(aKeySystem)) {
-    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-    return nullptr;
+  if (!IsSupportedKeySystem(mKeySystem)) {
+    promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return promise.forget();
   }
 
-  keys->mProxy = new CDMProxy(keys, aKeySystem);
+  mProxy = new CDMProxy(this, mKeySystem);
+
+  // Determine principal (at creation time) of the MediaKeys object.
+  nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetParentObject());
+  if (!sop) {
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
+  }
+  mPrincipal = sop->GetPrincipal();
+
+  // Determine principal of the "top-level" window; the principal of the
+  // page that will display in the URL bar.
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetParentObject());
+  if (!window) {
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
+  }
+  nsCOMPtr<nsIDOMWindow> topWindow;
+  window->GetTop(getter_AddRefs(topWindow));
+  nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow);
+  if (!top || !top->GetExtantDoc()) {
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
+  }
+  
+  mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal();
+
+  if (!mPrincipal || !mTopLevelPrincipal) {
+    NS_WARNING("Failed to get principals when creating MediaKeys");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
+  }
+
+  nsAutoString origin;
+  nsresult rv = nsContentUtils::GetUTFOrigin(mPrincipal, origin);
+  if (NS_FAILED(rv)) {
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
+  }
+  nsAutoString topLevelOrigin;
+  rv = nsContentUtils::GetUTFOrigin(mTopLevelPrincipal, topLevelOrigin);
+  if (NS_FAILED(rv)) {
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
+  }
+
+  if (!window) {
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
+  }
+  nsIDocument* doc = window->GetExtantDoc();
+  const bool inPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc);
+
+  EME_LOG("MediaKeys::Create() (%s, %s), %s",
+          NS_ConvertUTF16toUTF8(origin).get(),
+          NS_ConvertUTF16toUTF8(topLevelOrigin).get(),
+          (inPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
 
   // The CDMProxy's initialization is asynchronous. The MediaKeys is
   // refcounted, and its instance is returned to JS by promise once
   // it's been initialized. No external refs exist to the MediaKeys while
   // we're waiting for the promise to be resolved, so we must hold a
   // reference to the new MediaKeys object until it's been created,
   // or its creation has failed. Store the id of the promise returned
   // here, and hold a self-reference until that promise is resolved or
   // rejected.
-  MOZ_ASSERT(!keys->mCreatePromiseId, "Should only be created once!");
-  keys->mCreatePromiseId = keys->StorePromise(promise);
-  keys->AddRef();
-  keys->mProxy->Init(keys->mCreatePromiseId);
+  MOZ_ASSERT(!mCreatePromiseId, "Should only be created once!");
+  mCreatePromiseId = StorePromise(promise);
+  AddRef();
+  mProxy->Init(mCreatePromiseId,
+               origin,
+               topLevelOrigin,
+               inPrivateBrowsing);
 
   return promise.forget();
 }
 
 void
-MediaKeys::OnCDMCreated(PromiseId aId)
+MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId)
 {
   nsRefPtr<Promise> promise(RetrievePromise(aId));
   if (!promise) {
     NS_WARNING("MediaKeys tried to resolve a non-existent promise");
     return;
   }
+  mNodeId = aNodeId;
   nsRefPtr<MediaKeys> keys(this);
   promise->MaybeResolve(keys);
   if (mCreatePromiseId == aId) {
     Release();
   }
 }
 
 already_AddRefed<MediaKeySession>
@@ -361,36 +428,68 @@ MediaKeys::OnSessionClosed(MediaKeySessi
 already_AddRefed<MediaKeySession>
 MediaKeys::GetSession(const nsAString& aSessionId)
 {
   nsRefPtr<MediaKeySession> session;
   mKeySessions.Get(aSessionId, getter_AddRefs(session));
   return session.forget();
 }
 
+const nsCString&
+MediaKeys::GetNodeId() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  return mNodeId;
+}
+
+bool
+MediaKeys::IsBoundToMediaElement() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  return mElement != nullptr;
+}
+
 nsresult
-MediaKeys::GetOrigin(nsString& aOutOrigin)
+MediaKeys::Bind(HTMLMediaElement* aElement)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  // TODO: Bug 1035637, return a combination of origin and URL bar origin.
+  if (IsBoundToMediaElement()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mElement = aElement;
+  nsresult rv = CheckPrincipals();
+  if (NS_FAILED(rv)) {
+    mElement = nullptr;
+    return rv;
+  }
+
+  return NS_OK;
+}
 
-  nsIPrincipal* principal = nullptr;
-  nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(GetParentObject());
-  nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
-    do_QueryInterface(pWindow);
-  if (scriptPrincipal) {
-    principal = scriptPrincipal->GetPrincipal();
+nsresult
+MediaKeys::CheckPrincipals()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!IsBoundToMediaElement()) {
+    return NS_ERROR_FAILURE;
   }
-  NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
-
-  nsresult res = nsContentUtils::GetUTFOrigin(principal, aOutOrigin);
 
-  EME_LOG("EME Origin = '%s'", NS_ConvertUTF16toUTF8(aOutOrigin).get());
+  nsRefPtr<nsIPrincipal> elementPrincipal(mElement->GetCurrentPrincipal());
+  nsRefPtr<nsIPrincipal> elementTopLevelPrincipal(mElement->GetTopLevelPrincipal());
+  if (!elementPrincipal ||
+      !mPrincipal ||
+      !elementPrincipal->Equals(mPrincipal) ||
+      !elementTopLevelPrincipal ||
+      !mTopLevelPrincipal ||
+      !elementTopLevelPrincipal->Equals(mTopLevelPrincipal)) {
+    return NS_ERROR_FAILURE;
+  }
 
-  return res;
+  return NS_OK;
 }
 
 bool
 CopyArrayBufferViewOrArrayBufferData(const ArrayBufferViewOrArrayBuffer& aBufferOrView,
                                      nsTArray<uint8_t>& aOutData)
 {
   if (aBufferOrView.IsArrayBuffer()) {
     const ArrayBuffer& buffer = aBufferOrView.GetAsArrayBuffer();
--- a/content/media/eme/MediaKeys.h
+++ b/content/media/eme/MediaKeys.h
@@ -13,24 +13,26 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsRefPtrHashtable.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/MediaKeysBinding.h"
 #include "mozilla/dom/UnionTypes.h"
+#include "mozIGeckoMediaPluginService.h"
 
 namespace mozilla {
 
 class CDMProxy;
 
 namespace dom {
 
 class MediaKeySession;
+class HTMLMediaElement;
 
 typedef nsRefPtrHashtable<nsStringHashKey, MediaKeySession> KeySessionHashMap;
 typedef nsRefPtrHashtable<nsUint32HashKey, dom::Promise> PromiseHashMap;
 typedef nsRefPtrHashtable<nsUint32HashKey, MediaKeySession> PendingKeySessionsHashMap;
 typedef uint32_t PromiseId;
 
 // Helper function to extract data coming in from JS in an
 // (ArrayBuffer or ArrayBufferView) IDL typed function argument.
@@ -50,16 +52,18 @@ public:
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeys)
 
   MediaKeys(nsPIDOMWindow* aParentWindow, const nsAString& aKeySystem);
 
   nsPIDOMWindow* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
+  nsresult Bind(HTMLMediaElement* aElement);
+
   // Javascript: readonly attribute DOMString keySystem;
   void GetKeySystem(nsString& retval) const;
 
   // JavaScript: MediaKeys.createSession()
   already_AddRefed<MediaKeySession> CreateSession(SessionType aSessionType,
                                                   ErrorResult& aRv);
 
   // JavaScript: MediaKeys.SetServerCertificate()
@@ -77,17 +81,17 @@ public:
                                                const nsAString& aKeySystem,
                                                const Optional<nsAString>& aInitDataType,
                                                const Optional<nsAString>& aContentType,
                                                const Optional<nsAString>& aCapability);
 
   already_AddRefed<MediaKeySession> GetSession(const nsAString& aSessionId);
 
   // Called once a Create() operation succeeds.
-  void OnCDMCreated(PromiseId aId);
+  void OnCDMCreated(PromiseId aId, const nsACString& aNodeId);
   // Called when GenerateRequest or Load have been called on a MediaKeySession
   // and we are waiting for its initialisation to finish.
   void OnSessionPending(PromiseId aId, MediaKeySession* aSession);
   // Called once a CreateSession succeeds.
   void OnSessionCreated(PromiseId aId, const nsAString& aSessionId);
   // Called once a LoadSession succeeds.
   void OnSessionLoaded(PromiseId aId, bool aSuccess);
   // Called once a session has closed.
@@ -102,33 +106,50 @@ public:
   // promises to be resolved.
   PromiseId StorePromise(Promise* aPromise);
 
   // Reject promise with DOMException corresponding to aExceptionCode.
   void RejectPromise(PromiseId aId, nsresult aExceptionCode);
   // Resolves promise with "undefined".
   void ResolvePromise(PromiseId aId);
 
-  nsresult GetOrigin(nsString& aOutOrigin);
+  const nsCString& GetNodeId() const;
 
   void Shutdown();
 
+  // Returns true if this MediaKeys has been bound to a media element.
+  bool IsBoundToMediaElement() const;
+
+  // Return NS_OK if the principals are the same as when the MediaKeys
+  // was created, failure otherwise.
+  nsresult CheckPrincipals();
+
 private:
 
+  bool IsInPrivateBrowsing();
+  already_AddRefed<Promise> Init(ErrorResult& aRv);
+
   // Removes promise from mPromises, and returns it.
   already_AddRefed<Promise> RetrievePromise(PromiseId aId);
 
   // Owning ref to proxy. The proxy has a weak reference back to the MediaKeys,
   // and the MediaKeys destructor clears the proxy's reference to the MediaKeys.
   nsRefPtr<CDMProxy> mProxy;
 
+  nsRefPtr<HTMLMediaElement> mElement;
+
   nsCOMPtr<nsPIDOMWindow> mParent;
   nsString mKeySystem;
+  nsCString mNodeId;
   KeySessionHashMap mKeySessions;
   PromiseHashMap mPromises;
   PendingKeySessionsHashMap mPendingSessions;
   PromiseId mCreatePromiseId;
+
+  nsRefPtr<nsIPrincipal> mPrincipal;
+  nsRefPtr<nsIPrincipal> mTopLevelPrincipal;
+
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mediakeys_h__
--- a/content/media/fmp4/eme/EMEAudioDecoder.cpp
+++ b/content/media/fmp4/eme/EMEAudioDecoder.cpp
@@ -237,17 +237,17 @@ nsresult
 EMEAudioDecoder::GmpInit()
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_LITERAL_CSTRING("aac"));
   tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
   nsresult rv = mMPS->GetGMPAudioDecoder(&tags,
-                                         mProxy->GetOrigin(),
+                                         mProxy->GetNodeId(),
                                          &mGMP);
   NS_ENSURE_SUCCESS(rv, rv);
   MOZ_ASSERT(mGMP);
 
   mAudioRate = mConfig.samples_per_second;
   mAudioBytesPerSample = mConfig.bits_per_sample / 8;
   mAudioChannels = mConfig.channel_count;
 
--- a/content/media/fmp4/eme/EMEH264Decoder.cpp
+++ b/content/media/fmp4/eme/EMEH264Decoder.cpp
@@ -228,17 +228,17 @@ nsresult
 EMEH264Decoder::GmpInit()
 {
   MOZ_ASSERT(IsOnGMPThread());
 
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_LITERAL_CSTRING("h264"));
   tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
   nsresult rv = mMPS->GetGMPVideoDecoder(&tags,
-                                         mProxy->GetOrigin(),
+                                         mProxy->GetNodeId(),
                                          &mHost,
                                          &mGMP);
   NS_ENSURE_SUCCESS(rv, rv);
   MOZ_ASSERT(mHost && mGMP);
 
   GMPVideoCodec codec;
   memset(&codec, 0, sizeof(codec));
 
--- a/content/media/gmp/GMPChild.cpp
+++ b/content/media/gmp/GMPChild.cpp
@@ -24,16 +24,31 @@
 using mozilla::dom::CrashReporterChild;
 
 #ifdef XP_WIN
 #include <stdlib.h> // for _exit()
 #else
 #include <unistd.h> // for _exit()
 #endif
 
+#if defined(XP_WIN)
+// In order to provide EME plugins with a "device binding" capability,
+// in the parent we generate and store some random bytes as salt for every
+// (origin, urlBarOrigin) pair that uses EME. We store these bytes so
+// that every time we revisit the same origin we get the same salt.
+// We send this salt to the child on startup. The child collects some
+// device specific data and munges that with the salt to create the
+// "node id" that we expose to EME plugins. It then overwrites the device
+// specific data, and activates the sandbox.
+#define HASH_NODE_ID_WITH_DEVICE_ID 1
+#include "rlz/lib/machine_id.h"
+#include "rlz/lib/string_utils.h"
+#include "mozilla/SHA1.h"
+#endif
+
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
 #define TARGET_SANDBOX_EXPORTS
 #include "mozilla/sandboxTarget.h"
 #elif defined (MOZ_GMP_SANDBOX)
 #if defined(XP_LINUX) || defined(XP_MACOSX)
 #include "mozilla/Sandbox.h"
 #endif
 #endif
@@ -263,30 +278,68 @@ GMPChild::Init(const std::string& aPlugi
   if (!Open(aChannel, aParentProcessHandle, aIOLoop)) {
     return false;
   }
 
 #ifdef MOZ_CRASHREPORTER
   SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
 #endif
 
-#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   mPluginPath = aPluginPath;
   return true;
-#endif
+}
+
+bool
+GMPChild::RecvSetNodeId(const nsCString& aNodeId)
+{
+#ifdef HASH_NODE_ID_WITH_DEVICE_ID
+  if (!aNodeId.IsEmpty() && !aNodeId.EqualsLiteral("null")) {
+    string16 deviceId;
+    int volumeId;
+    if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) {
+      return false;
+    }
 
+    // TODO: Switch to SHA256.
+    mozilla::SHA1Sum hash;
+    hash.update(deviceId.c_str(), deviceId.size() * sizeof(string16::value_type));
+    hash.update(aNodeId.get(), aNodeId.Length());
+    hash.update(&volumeId, sizeof(int));
+    uint8_t digest[mozilla::SHA1Sum::kHashSize];
+    hash.finish(digest);
+    if (!rlz_lib::BytesToString(digest, mozilla::SHA1Sum::kHashSize, &mNodeId)) {
+      return false;
+    }
+
+    // Overwrite device id as it could potentially identify the user, so
+    // there's no chance a GMP can read it and use it for identity tracking.
+    volumeId = 0;
+    memset(&deviceId.front(), '*', sizeof(string16::value_type) * deviceId.size());
+    deviceId = L"";
+  } else {
+    mNodeId = "null";
+  }
+#else
+  mNodeId = std::string(aNodeId.BeginReading(), aNodeId.EndReading());
+#endif
+  return true;
+}
+
+bool
+GMPChild::RecvStartPlugin()
+{
 #ifdef XP_WIN
-  PreLoadLibraries(aPluginPath);
+  PreLoadLibraries(mPluginPath);
 #endif
 
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
   mozilla::SandboxTarget::Instance()->StartSandbox();
 #endif
 
-  return LoadPluginLibrary(aPluginPath);
+  return LoadPluginLibrary(mPluginPath);
 }
 
 #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
 bool
 GMPChild::PreLoadLibraries(const std::string& aPluginPath)
 {
@@ -494,17 +547,17 @@ GMPChild::DeallocPGMPVideoDecoderChild(P
 {
   delete aActor;
   return true;
 }
 
 PGMPDecryptorChild*
 GMPChild::AllocPGMPDecryptorChild()
 {
-  GMPDecryptorChild* actor = new GMPDecryptorChild(this);
+  GMPDecryptorChild* actor = new GMPDecryptorChild(this, mNodeId);
   actor->AddRef();
   return actor;
 }
 
 bool
 GMPChild::DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor)
 {
   static_cast<GMPDecryptorChild*>(aActor)->Release();
--- a/content/media/gmp/GMPChild.h
+++ b/content/media/gmp/GMPChild.h
@@ -45,16 +45,20 @@ public:
 
   // GMPSharedMem
   virtual void CheckThread() MOZ_OVERRIDE;
 
   // GMPAsyncShutdownHost
   void ShutdownComplete() MOZ_OVERRIDE;
 
 private:
+
+  virtual bool RecvSetNodeId(const nsCString& aNodeId) MOZ_OVERRIDE;
+  virtual bool RecvStartPlugin() MOZ_OVERRIDE;
+
   virtual PCrashReporterChild* AllocPCrashReporterChild(const NativeThreadId& aThread) MOZ_OVERRIDE;
   virtual bool DeallocPCrashReporterChild(PCrashReporterChild*) MOZ_OVERRIDE;
 
   virtual PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild() MOZ_OVERRIDE;
   virtual bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) MOZ_OVERRIDE;
   virtual bool RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor) MOZ_OVERRIDE;
 
   virtual PGMPVideoEncoderChild* AllocPGMPVideoEncoderChild() MOZ_OVERRIDE;
@@ -83,18 +87,19 @@ private:
 
   GMPAsyncShutdown* mAsyncShutdown;
   nsRefPtr<GMPTimerChild> mTimerChild;
   nsRefPtr<GMPStorageChild> mStorage;
 
   PRLibrary* mLib;
   GMPGetAPIFunc mGetAPIFunc;
   MessageLoop* mGMPMessageLoop;
+  std::string mPluginPath;
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
-  std::string mPluginPath;
   nsCString mPluginBinaryPath;
 #endif
+  std::string mNodeId;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPChild_h_
--- a/content/media/gmp/GMPDecryptorChild.cpp
+++ b/content/media/gmp/GMPDecryptorChild.cpp
@@ -21,19 +21,20 @@
         FROM_HERE, NewRunnableMethod(this, &GMPDecryptorChild::_func, __VA_ARGS__) \
       ); \
     } \
   } while(false)
 
 namespace mozilla {
 namespace gmp {
 
-GMPDecryptorChild::GMPDecryptorChild(GMPChild* aPlugin)
+GMPDecryptorChild::GMPDecryptorChild(GMPChild* aPlugin, const std::string& aNodeId)
   : mSession(nullptr)
   , mPlugin(aPlugin)
+  , mNodeId(aNodeId)
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPDecryptorChild::~GMPDecryptorChild()
 {
 }
 
@@ -171,19 +172,18 @@ GMPDecryptorChild::SetCapabilities(uint6
 {
   CALL_ON_GMP_THREAD(SendSetCaps, aCaps);
 }
 
 void
 GMPDecryptorChild::GetNodeId(const char** aOutNodeId,
                              uint32_t* aOutNodeIdLength)
 {
-  static const char* id = "placeholder_node_id";
-  *aOutNodeId = id;
-  *aOutNodeIdLength = strlen(id);
+  *aOutNodeId = mNodeId.c_str();
+  *aOutNodeIdLength = mNodeId.size();
 }
 
 void
 GMPDecryptorChild::GetSandboxVoucher(const uint8_t** aVoucher,
                                      uint8_t* aVoucherLength)
 {
   const char* voucher = "placeholder_sandbox_voucher.";
   *aVoucher = (uint8_t*)voucher;
--- a/content/media/gmp/GMPDecryptorChild.h
+++ b/content/media/gmp/GMPDecryptorChild.h
@@ -5,30 +5,31 @@
 
 #ifndef GMPDecryptorChild_h_
 #define GMPDecryptorChild_h_
 
 #include "mozilla/gmp/PGMPDecryptorChild.h"
 #include "gmp-decryption.h"
 #include "mozilla/gmp/GMPTypes.h"
 #include "GMPEncryptedBufferDataImpl.h"
+#include <string>
 
 namespace mozilla {
 namespace gmp {
 
 class GMPChild;
 
 class GMPDecryptorChild : public GMPDecryptorCallback
                         , public GMPDecryptorHost
                         , public PGMPDecryptorChild
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPDecryptorChild);
 
-  explicit GMPDecryptorChild(GMPChild* aPlugin);
+  explicit GMPDecryptorChild(GMPChild* aPlugin, const std::string& aNodeId);
 
   void Init(GMPDecryptor* aSession);
 
   // GMPDecryptorCallback
   virtual void ResolveNewSessionPromise(uint32_t aPromiseId,
                                         const char* aSessionId,
                                         uint32_t aSessionIdLength) MOZ_OVERRIDE;
   virtual void ResolveLoadSessionPromise(uint32_t aPromiseId,
@@ -117,14 +118,16 @@ private:
                                         const nsTArray<uint8_t>& aServerCert) MOZ_OVERRIDE;
 
   virtual bool RecvDecryptingComplete() MOZ_OVERRIDE;
 
   // GMP's GMPDecryptor implementation.
   // Only call into this on the (GMP process) main thread.
   GMPDecryptor* mSession;
   GMPChild* mPlugin;
+
+  const std::string mNodeId;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPDecryptorChild_h_
--- a/content/media/gmp/GMPParent.cpp
+++ b/content/media/gmp/GMPParent.cpp
@@ -145,16 +145,32 @@ GMPParent::LoadProcess()
 
     bool opened = Open(mProcess->GetChannel(), mProcess->GetChildProcessHandle());
     if (!opened) {
       mProcess->Delete();
       mProcess = nullptr;
       return NS_ERROR_FAILURE;
     }
     LOGD(("%s::%s: Created new process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
+
+    bool ok = SendSetNodeId(mNodeId);
+    if (!ok) {
+      mProcess->Delete();
+      mProcess = nullptr;
+      return NS_ERROR_FAILURE;
+    }
+    LOGD(("%s::%s: Failed to send node id %p", __CLASS__, __FUNCTION__, (void *)mProcess));
+
+    ok = SendStartPlugin();
+    if (!ok) {
+      mProcess->Delete();
+      mProcess = nullptr;
+      return NS_ERROR_FAILURE;
+    }
+    LOGD(("%s::%s: Failed to send start %p", __CLASS__, __FUNCTION__, (void *)mProcess));
   }
 
   mState = GMPStateLoaded;
 
   return NS_OK;
 }
 
 void
@@ -675,33 +691,37 @@ GMPParent::DeallocPGMPAudioDecoderParent
   GMPAudioDecoderParent* vdp = static_cast<GMPAudioDecoderParent*>(aActor);
   NS_RELEASE(vdp);
   return true;
 }
 
 PGMPStorageParent*
 GMPParent::AllocPGMPStorageParent()
 {
-  GMPStorageParent* p = new GMPStorageParent(mOrigin, this);
+  GMPStorageParent* p = new GMPStorageParent(mNodeId, this);
   mStorage.AppendElement(p); // Addrefs, released in DeallocPGMPStorageParent.
   return p;
 }
 
 bool
 GMPParent::DeallocPGMPStorageParent(PGMPStorageParent* aActor)
 {
   GMPStorageParent* p = static_cast<GMPStorageParent*>(aActor);
   p->Shutdown();
   mStorage.RemoveElement(p);
   return true;
 }
 
 bool
-GMPParent::RecvPGMPStorageConstructor(PGMPStorageParent* actor)
+GMPParent::RecvPGMPStorageConstructor(PGMPStorageParent* aActor)
 {
+  GMPStorageParent* p  = (GMPStorageParent*)aActor;
+  if (NS_WARN_IF(NS_FAILED(p->Init()))) {
+    return false;
+  }
   return true;
 }
 
 bool
 GMPParent::RecvPGMPTimerConstructor(PGMPTimerParent* actor)
 {
   return true;
 }
@@ -872,34 +892,34 @@ GMPParent::ReadGMPMetaData()
   if (mCapabilities.IsEmpty()) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 bool
-GMPParent::CanBeSharedCrossOrigin() const
+GMPParent::CanBeSharedCrossNodeIds() const
 {
-  return mOrigin.IsEmpty();
+  return mNodeId.IsEmpty();
 }
 
 bool
-GMPParent::CanBeUsedFrom(const nsAString& aOrigin) const
+GMPParent::CanBeUsedFrom(const nsACString& aNodeId) const
 {
-  return (mOrigin.IsEmpty() && State() == GMPStateNotLoaded) ||
-         mOrigin.Equals(aOrigin);
+  return (mNodeId.IsEmpty() && State() == GMPStateNotLoaded) ||
+         mNodeId == aNodeId;
 }
 
 void
-GMPParent::SetOrigin(const nsAString& aOrigin)
+GMPParent::SetNodeId(const nsACString& aNodeId)
 {
-  MOZ_ASSERT(!aOrigin.IsEmpty());
-  MOZ_ASSERT(CanBeUsedFrom(aOrigin));
-  mOrigin = aOrigin;
+  MOZ_ASSERT(!aNodeId.IsEmpty());
+  MOZ_ASSERT(CanBeUsedFrom(aNodeId));
+  mNodeId = aNodeId;
 }
 
 bool
 GMPParent::RecvAsyncShutdownRequired()
 {
   LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
   mAsyncShutdownRequired = true;
   mService->AsyncShutdownNeeded(this);
--- a/content/media/gmp/GMPParent.h
+++ b/content/media/gmp/GMPParent.h
@@ -94,36 +94,38 @@ public:
   void DecryptorDestroyed(GMPDecryptorParent* aSession);
 
   nsresult GetGMPAudioDecoder(GMPAudioDecoderParent** aGMPAD);
   void AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder);
 
   GMPState State() const;
   nsIThread* GMPThread();
 
-  // A GMP can either be a single instance shared across all origins (like
+  // A GMP can either be a single instance shared across all NodeIds (like
   // in the OpenH264 case), or we can require a new plugin instance for every
-  // origin running the plugin (as in the EME plugin case).
+  // NodeIds running the plugin (as in the EME plugin case).
   //
-  // Plugins are associated with an origin by calling SetOrigin() before
+  // A NodeId is a hash of the ($urlBarOrigin, $ownerDocOrigin) pair.
+  //
+  // Plugins are associated with an NodeIds by calling SetNodeId() before
   // loading.
   //
-  // If a plugin has no origin specified and it is loaded, it is assumed to
-  // be shared across origins.
+  // If a plugin has no NodeId specified and it is loaded, it is assumed to
+  // be shared across NodeIds.
 
-  // Specifies that a GMP can only work with the specified origin.
-  void SetOrigin(const nsAString& aOrigin);
+  // Specifies that a GMP can only work with the specified NodeIds.
+  void SetNodeId(const nsACString& aNodeId);
 
-  // Returns true if a plugin can be or is being used across multiple origins.
-  bool CanBeSharedCrossOrigin() const;
+  // Returns true if a plugin can be or is being used across multiple NodeIds.
+  bool CanBeSharedCrossNodeIds() const;
 
-  // A GMP can be used from an origin if it's already been set to work with
-  // that origin, or if it's not been set to work with any origin and has
-  // not yet been loaded (i.e. it's not shared across origins).
-  bool CanBeUsedFrom(const nsAString& aOrigin) const;
+  // A GMP can be used from a NodeId if it's already been set to work with
+  // that NodeId, or if it's not been set to work with any NodeId and has
+  // not yet been loaded (i.e. it's not shared across NodeIds).
+  bool CanBeUsedFrom(const nsACString& aNodeId) const;
 
   already_AddRefed<nsIFile> GetDirectory() {
     return nsCOMPtr<nsIFile>(mDirectory).forget();
   }
 
   // GMPSharedMem
   virtual void CheckThread() MOZ_OVERRIDE;
 
@@ -179,19 +181,19 @@ private:
 
   nsTArray<nsRefPtr<GMPVideoDecoderParent>> mVideoDecoders;
   nsTArray<nsRefPtr<GMPVideoEncoderParent>> mVideoEncoders;
   nsTArray<nsRefPtr<GMPDecryptorParent>> mDecryptors;
   nsTArray<nsRefPtr<GMPAudioDecoderParent>> mAudioDecoders;
   nsTArray<nsRefPtr<GMPTimerParent>> mTimers;
   nsTArray<nsRefPtr<GMPStorageParent>> mStorage;
   nsCOMPtr<nsIThread> mGMPThread;
-  // Origin the plugin is assigned to, or empty if the the plugin is not
-  // assigned to an origin.
-  nsAutoString mOrigin;
+  // NodeId the plugin is assigned to, or empty if the the plugin is not
+  // assigned to a NodeId.
+  nsAutoCString mNodeId;
 
   bool mAsyncShutdownRequired;
   bool mAsyncShutdownInProgress;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "GMPService.h"
+#include "prio.h"
 #include "prlog.h"
 #include "GMPParent.h"
 #include "GMPVideoDecoderParent.h"
 #include "nsIObserverService.h"
 #include "GeckoChildProcessHost.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SyncRunnable.h"
@@ -17,19 +18,25 @@
 #include "nsNativeCharsetUtils.h"
 #include "nsIConsoleService.h"
 #include "mozilla/unused.h"
 #include "GMPDecryptorParent.h"
 #include "GMPAudioDecoderParent.h"
 #include "nsComponentManagerUtils.h"
 #include "mozilla/Preferences.h"
 #include "runnable_utils.h"
+#include "VideoUtils.h"
 #if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
 #include "mozilla/Sandbox.h"
 #endif
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsHashKeys.h"
+#include "nsIFile.h"
 
 namespace mozilla {
 
 #ifdef LOG
 #undef LOG
 #endif
 
 #ifdef PR_LOGGING
@@ -149,34 +156,56 @@ GeckoMediaPluginService::GeckoMediaPlugi
 }
 
 GeckoMediaPluginService::~GeckoMediaPluginService()
 {
   MOZ_ASSERT(mPlugins.IsEmpty());
   MOZ_ASSERT(mAsyncShutdownPlugins.IsEmpty());
 }
 
-void
+nsresult
 GeckoMediaPluginService::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
   MOZ_ASSERT(obsService);
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, "profile-change-teardown", false)));
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false)));
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, "last-pb-context-exited", false)));
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefs) {
     prefs->AddObserver("media.gmp.plugin.crash", this, false);
   }
 
+#ifndef MOZ_WIDGET_GONK
+  // Directory service is main thread only, so cache the profile dir here
+  // so that we can use it off main thread.
+  // We only do this on non-B2G, as this fails in multi-process Gecko.
+  // TODO: Make this work in multi-process Gecko.
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mStorageBaseDir));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = mStorageBaseDir->AppendNative(NS_LITERAL_CSTRING("gmp"));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = mStorageBaseDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
+  if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) {
+    return rv;
+  }
+#endif
+
   // Kick off scanning for plugins
   nsCOMPtr<nsIThread> thread;
-  unused << GetThread(getter_AddRefs(thread));
+  return GetThread(getter_AddRefs(thread));
 }
 
 void
 AbortWaitingForGMPAsyncShutdown(nsITimer* aTimer, void* aClosure)
 {
   NS_WARNING("Timed out waiting for GMP async shutdown!");
   nsRefPtr<GeckoMediaPluginService> service = sSingletonService.get();
   if (service) {
@@ -283,16 +312,23 @@ GeckoMediaPluginService::Observe(nsISupp
       // See bug 1057908.
       MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default || mShuttingDown);
       mGMPThread.swap(gmpThread);
     }
 
     if (gmpThread) {
       gmpThread->Shutdown();
     }
+  } else if (!strcmp("last-pb-context-exited", aTopic)) {
+    // When Private Browsing mode exits, all we need to do is clear
+    // mTempNodeIds. This drops all the node ids we've cached in memory
+    // for PB origin-pairs. If we try to open an origin-pair for non-PB
+    // mode, we'll get the NodeId salt stored on-disk, and if we try to
+    // open a PB mode origin-pair, we'll re-generate new salt.
+    mTempNodeIds.Clear();
   }
   return NS_OK;
 }
 
 // always call with getter_AddRefs, because it does
 NS_IMETHODIMP
 GeckoMediaPluginService::GetThread(nsIThread** aThread)
 {
@@ -319,28 +355,28 @@ GeckoMediaPluginService::GetThread(nsITh
   NS_ADDREF(mGMPThread);
   *aThread = mGMPThread;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
-                                            const nsAString& aOrigin,
+                                            const nsACString& aNodeId,
                                             GMPAudioDecoderProxy** aGMPAD)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aGMPAD);
 
   if (mShuttingDownOnGMPThread) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
+  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aNodeId,
                                                NS_LITERAL_CSTRING("decode-audio"),
                                                *aTags);
   if (!gmp) {
     return NS_ERROR_FAILURE;
   }
 
   GMPAudioDecoderParent* gmpADP;
   nsresult rv = gmp->GetGMPAudioDecoder(&gmpADP);
@@ -350,30 +386,30 @@ GeckoMediaPluginService::GetGMPAudioDeco
 
   *aGMPAD = gmpADP;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
-                                            const nsAString& aOrigin,
+                                            const nsACString& aNodeId,
                                             GMPVideoHost** aOutVideoHost,
                                             GMPVideoDecoderProxy** aGMPVD)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aOutVideoHost);
   NS_ENSURE_ARG(aGMPVD);
 
   if (mShuttingDownOnGMPThread) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
+  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aNodeId,
                                                NS_LITERAL_CSTRING("decode-video"),
                                                *aTags);
 #ifdef PR_LOGGING
   nsCString api = (*aTags)[0];
   LOGD(("%s: %p returning %p for api %s", __FUNCTION__, (void *)this, (void *)gmp, api.get()));
 #endif
   if (!gmp) {
     return NS_ERROR_FAILURE;
@@ -389,30 +425,30 @@ GeckoMediaPluginService::GetGMPVideoDeco
   *aGMPVD = gmpVDP;
   *aOutVideoHost = &gmpVDP->Host();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
-                                            const nsAString& aOrigin,
+                                            const nsACString& aNodeId,
                                             GMPVideoHost** aOutVideoHost,
                                             GMPVideoEncoderProxy** aGMPVE)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aOutVideoHost);
   NS_ENSURE_ARG(aGMPVE);
 
   if (mShuttingDownOnGMPThread) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
+  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aNodeId,
                                                NS_LITERAL_CSTRING("encode-video"),
                                                *aTags);
 #ifdef PR_LOGGING
   nsCString api = (*aTags)[0];
   LOGD(("%s: %p returning %p for api %s", __FUNCTION__, (void *)this, (void *)gmp, api.get()));
 #endif
   if (!gmp) {
     return NS_ERROR_FAILURE;
@@ -427,17 +463,17 @@ GeckoMediaPluginService::GetGMPVideoEnco
   *aGMPVE = gmpVEP;
   *aOutVideoHost = &gmpVEP->Host();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
-                                         const nsAString& aOrigin,
+                                         const nsACString& aNodeId,
                                          GMPDecryptorProxy** aDecryptor)
 {
 #if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
   if (!mozilla::CanSandboxMediaPlugin()) {
     NS_WARNING("GeckoMediaPluginService::GetGMPDecryptor: "
                "EME decryption not available without sandboxing support.");
     return NS_ERROR_NOT_AVAILABLE;
   }
@@ -446,17 +482,17 @@ GeckoMediaPluginService::GetGMPDecryptor
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aDecryptor);
 
   if (mShuttingDownOnGMPThread) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
+  nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aNodeId,
                                                NS_LITERAL_CSTRING("eme-decrypt"),
                                                *aTags);
   if (!gmp) {
     return NS_ERROR_FAILURE;
   }
 
   GMPDecryptorParent* ksp;
   nsresult rv = gmp->GetGMPDecryptor(&ksp);
@@ -653,38 +689,38 @@ GeckoMediaPluginService::RemovePluginDir
     return rv;
   }
   nsCOMPtr<nsIRunnable> r = new PathRunnable(this, aDirectory, false);
   thread->Dispatch(r, NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-GeckoMediaPluginService::HasPluginForAPI(const nsAString& aOrigin,
+GeckoMediaPluginService::HasPluginForAPI(const nsACString& aNodeId,
                                          const nsACString& aAPI,
                                          nsTArray<nsCString>* aTags,
                                          bool* aResult)
 {
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aResult);
 
   nsCString temp(aAPI);
-  GMPParent *parent = SelectPluginForAPI(aOrigin, temp, *aTags, false);
+  GMPParent *parent = SelectPluginForAPI(aNodeId, temp, *aTags, false);
   *aResult = !!parent;
 
   return NS_OK;
 }
 
 GMPParent*
-GeckoMediaPluginService::SelectPluginForAPI(const nsAString& aOrigin,
+GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
                                             const nsCString& aAPI,
                                             const nsTArray<nsCString>& aTags,
-                                            bool aCloneCrossOrigin)
+                                            bool aCloneCrossNodeIds)
 {
-  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread || !aCloneCrossOrigin,
+  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread || !aCloneCrossNodeIds,
              "Can't clone GMP plugins on non-GMP threads.");
 
   GMPParent* gmpToClone = nullptr;
   {
     MutexAutoLock lock(mMutex);
     for (uint32_t i = 0; i < mPlugins.Length(); i++) {
       GMPParent* gmp = mPlugins[i];
       bool supportsAllTags = true;
@@ -693,39 +729,38 @@ GeckoMediaPluginService::SelectPluginFor
         if (!gmp->SupportsAPI(aAPI, tag)) {
           supportsAllTags = false;
           break;
         }
       }
       if (!supportsAllTags) {
         continue;
       }
-      if (aOrigin.IsEmpty()) {
-        if (gmp->CanBeSharedCrossOrigin()) {
+      if (aNodeId.IsEmpty()) {
+        if (gmp->CanBeSharedCrossNodeIds()) {
           return gmp;
         }
-      } else if (gmp->CanBeUsedFrom(aOrigin)) {
-        if (!aOrigin.IsEmpty()) {
-          gmp->SetOrigin(aOrigin);
-        }
+      } else if (gmp->CanBeUsedFrom(aNodeId)) {
+        MOZ_ASSERT(!aNodeId.IsEmpty());
+        gmp->SetNodeId(aNodeId);
         return gmp;
       }
 
       // This GMP has the correct type but has the wrong origin; hold on to it
       // in case we need to clone it.
       gmpToClone = gmp;
     }
   }
 
   // Plugin exists, but we can't use it due to cross-origin separation. Create a
   // new one.
-  if (aCloneCrossOrigin && gmpToClone) {
+  if (aCloneCrossNodeIds && gmpToClone) {
     GMPParent* clone = ClonePlugin(gmpToClone);
-    if (!aOrigin.IsEmpty()) {
-      clone->SetOrigin(aOrigin);
+    if (!aNodeId.IsEmpty()) {
+      clone->SetNodeId(aNodeId);
     }
     return clone;
   }
 
   return nullptr;
 }
 
 class CreateGMPParentTask : public nsRunnable {
@@ -850,10 +885,261 @@ GeckoMediaPluginService::ReAddOnGMPThrea
   MutexAutoLock lock(mMutex);
   mPlugins.RemoveElement(aOld);
 
   // Schedule aOld to be destroyed.  We can't destroy it from here since we
   // may be inside ActorDestroyed() for it.
   NS_DispatchToCurrentThread(WrapRunnableNM(&Dummy, aOld));
 }
 
+NS_IMETHODIMP
+GeckoMediaPluginService::GetStorageDir(nsIFile** aOutFile)
+{
+#ifndef MOZ_WIDGET_GONK
+  if (NS_WARN_IF(!mStorageBaseDir)) {
+    return NS_ERROR_FAILURE;
+  }
+  return mStorageBaseDir->Clone(aOutFile);
+#else
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+}
+
+static nsresult
+WriteToFile(nsIFile* aPath,
+            const nsCString& aFileName,
+            const nsCString& aData)
+{
+  nsCOMPtr<nsIFile> path;
+  nsresult rv = aPath->Clone(getter_AddRefs(path));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = path->AppendNative(aFileName);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  PRFileDesc* f = nullptr;
+  rv = path->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, PR_IRWXU, &f);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  int32_t len = PR_Write(f, aData.get(), aData.Length());
+  PR_Close(f);
+  if (NS_WARN_IF(len < 0 || (size_t)len != aData.Length())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+static nsresult
+ReadFromFile(nsIFile* aPath,
+             const nsCString& aFileName,
+             nsCString& aOutData,
+             int32_t aMaxLength)
+{
+  nsCOMPtr<nsIFile> path;
+  nsresult rv = aPath->Clone(getter_AddRefs(path));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = path->AppendNative(aFileName);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  PRFileDesc* f = nullptr;
+  rv = path->OpenNSPRFileDesc(PR_RDONLY | PR_CREATE_FILE, PR_IRWXU, &f);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  auto size = PR_Seek(f, 0, PR_SEEK_END);
+  PR_Seek(f, 0, PR_SEEK_SET);
+
+  if (size > aMaxLength) {
+    return NS_ERROR_FAILURE;
+  }
+  aOutData.SetLength(size);
+
+  auto len = PR_Read(f, aOutData.BeginWriting(), size);
+  PR_Close(f);
+  if (NS_WARN_IF(len != size)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GeckoMediaPluginService::IsPersistentStorageAllowed(const nsACString& aNodeId,
+                                                    bool* aOutAllowed)
+{
+  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+  NS_ENSURE_ARG(aOutAllowed);
+  *aOutAllowed = mPersistentStorageAllowed.Get(aNodeId);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GeckoMediaPluginService::GetNodeId(const nsAString& aOrigin,
+                                   const nsAString& aTopLevelOrigin,
+                                   bool aInPrivateBrowsing,
+                                   nsACString& aOutId)
+{
+  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
+  LOGD(("%s::%s: (%s, %s), %s", __CLASS__, __FUNCTION__,
+       NS_ConvertUTF16toUTF8(aOrigin).get(),
+       NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
+       (aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing")));
+
+#ifdef MOZ_WIDGET_GONK
+  NS_WARNING("GeckoMediaPluginService::GetNodeId Not implemented on B2G");
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+
+  nsresult rv;
+  const uint32_t NodeIdSaltLength = 32;
+
+  if (aOrigin.EqualsLiteral("null") ||
+      aOrigin.IsEmpty() ||
+      aTopLevelOrigin.EqualsLiteral("null") ||
+      aTopLevelOrigin.IsEmpty()) {
+    // At least one of the (origin, topLevelOrigin) is null or empty;
+    // probably a local file. Generate a random node id, and don't store
+    // it so that the GMP's storage is temporary and not shared.
+    nsAutoCString salt;
+    rv = GenerateRandomPathName(salt, NodeIdSaltLength);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    aOutId = salt;
+    mPersistentStorageAllowed.Put(salt, false);
+    return NS_OK;
+  }
+
+  const uint32_t hash = AddToHash(HashString(aOrigin),
+                                  HashString(aTopLevelOrigin));
+
+  if (aInPrivateBrowsing) {
+    // For PB mode, we store the node id, indexed by the origin pair,
+    // so that if the same origin pair is opened in this session, it gets
+    // the same node id.
+    nsCString* salt = nullptr;
+    if (!(salt = mTempNodeIds.Get(hash))) {
+      // No salt stored, generate and temporarily store some for this id.
+      nsAutoCString newSalt;
+      rv = GenerateRandomPathName(newSalt, NodeIdSaltLength);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      salt = new nsCString(newSalt);
+      mTempNodeIds.Put(hash, salt);
+      mPersistentStorageAllowed.Put(*salt, false);
+    }
+    aOutId = *salt;
+    return NS_OK;
+  }
+
+  // Otherwise, try to see if we've previously generated and stored salt
+  // for this origin pair.
+  nsCOMPtr<nsIFile> path; // $profileDir/gmp/
+  rv = GetStorageDir(getter_AddRefs(path));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = path->AppendNative(NS_LITERAL_CSTRING("id"));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // $profileDir/gmp/id/
+  rv = path->Create(nsIFile::DIRECTORY_TYPE, 0700);
+  if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsAutoCString hashStr;
+  hashStr.AppendInt((int64_t)hash);
+
+  // $profileDir/gmp/id/$hash
+  rv = path->AppendNative(hashStr);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = path->Create(nsIFile::DIRECTORY_TYPE, 0700);
+  if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIFile> saltFile;
+  rv = path->Clone(getter_AddRefs(saltFile));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = saltFile->AppendNative(NS_LITERAL_CSTRING("salt"));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsAutoCString salt;
+  bool exists = false;
+  rv = saltFile->Exists(&exists);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (!exists) {
+    // No stored salt for this origin. Generate salt, and store it and
+    // the origin on disk.
+    nsresult rv = GenerateRandomPathName(salt, NodeIdSaltLength);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    MOZ_ASSERT(salt.Length() == NodeIdSaltLength);
+
+    // $profileDir/gmp/id/$hash/salt
+    rv = WriteToFile(path, NS_LITERAL_CSTRING("salt"), salt);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    // $profileDir/gmp/id/$hash/origin
+    rv = WriteToFile(path,
+                     NS_LITERAL_CSTRING("origin"),
+                     NS_ConvertUTF16toUTF8(aOrigin));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    // $profileDir/gmp/id/$hash/topLevelOrigin
+    rv = WriteToFile(path,
+                     NS_LITERAL_CSTRING("topLevelOrigin"),
+                     NS_ConvertUTF16toUTF8(aTopLevelOrigin));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+  } else {
+    rv = ReadFromFile(path,
+                      NS_LITERAL_CSTRING("salt"),
+                      salt,
+                      NodeIdSaltLength);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  aOutId = salt;
+  mPersistentStorageAllowed.Put(salt, true);
+
+  return NS_OK;
+}
+
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/GMPService.h
+++ b/content/media/gmp/GMPService.h
@@ -12,48 +12,50 @@
 #include "nsTArray.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Monitor.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIThread.h"
 #include "nsThreadUtils.h"
 #include "nsITimer.h"
+#include "nsClassHashtable.h"
+#include "nsDataHashtable.h"
 
 template <class> struct already_AddRefed;
 
 namespace mozilla {
 namespace gmp {
 
 class GMPParent;
 
 class GeckoMediaPluginService MOZ_FINAL : public mozIGeckoMediaPluginService
                                         , public nsIObserver
 {
 public:
   static already_AddRefed<GeckoMediaPluginService> GetGeckoMediaPluginService();
 
   GeckoMediaPluginService();
-  void Init();
+  nsresult Init();
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_MOZIGECKOMEDIAPLUGINSERVICE
   NS_DECL_NSIOBSERVER
 
   void AsyncShutdownNeeded(GMPParent* aParent);
   void AsyncShutdownComplete(GMPParent* aParent);
   void AbortAsyncShutdown();
 
 private:
   ~GeckoMediaPluginService();
 
-  GMPParent* SelectPluginForAPI(const nsAString& aOrigin,
+  GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
                                 const nsCString& aAPI,
                                 const nsTArray<nsCString>& aTags,
-                                bool aCloneCrossOrigin = true);
+                                bool aCloneCrossNodeIds = true);
 
   void UnloadPlugins();
   void CrashPlugins();
   void SetAsyncShutdownComplete();
 
   void LoadFromEnvironment();
   void ProcessPossiblePlugin(nsIFile* aDir);
 
@@ -106,14 +108,26 @@ private:
   private:
     T mValue;
   };
 
   MainThreadOnly<bool> mWaitingForPluginsAsyncShutdown;
 
   nsTArray<nsRefPtr<GMPParent>> mAsyncShutdownPlugins; // GMP Thread only.
   nsCOMPtr<nsITimer> mAsyncShutdownTimeout; // GMP Thread only.
+
+#ifndef MOZ_WIDGET_GONK
+  nsCOMPtr<nsIFile> mStorageBaseDir;
+#endif
+
+  // Hashes of (origin,topLevelOrigin) to the node id for
+  // non-persistent sessions.
+  nsClassHashtable<nsUint32HashKey, nsCString> mTempNodeIds;
+
+  // Hashes node id to whether that node id is allowed to store data
+  // persistently on disk.
+  nsDataHashtable<nsCStringHashKey, bool> mPersistentStorageAllowed;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPService_h_
--- a/content/media/gmp/GMPStorageParent.cpp
+++ b/content/media/gmp/GMPStorageParent.cpp
@@ -3,19 +3,26 @@
  * 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 "GMPStorageParent.h"
 #include "mozilla/SyncRunnable.h"
 #include "plhash.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
+#include "nsAppDirectoryServiceDefs.h"
 #include "GMPParent.h"
 #include "gmp-storage.h"
 #include "mozilla/unused.h"
+#include "nsTHashtable.h"
+#include "nsDataHashtable.h"
+#include "prio.h"
+#include "mozIGeckoMediaPluginService.h"
+#include "nsContentCID.h"
+#include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 
 #ifdef LOG
 #undef LOG
 #endif
 
 #ifdef PR_LOGGING
@@ -30,92 +37,67 @@ extern PRLogModuleInfo* GetGMPLog();
 
 #ifdef __CLASS__
 #undef __CLASS__
 #endif
 #define __CLASS__ "GMPParent"
 
 namespace gmp {
 
-class GetTempDirTask : public nsRunnable
-{
-public:
-  NS_IMETHOD Run() {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    nsCOMPtr<nsIFile> tmpFile;
-    nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    tmpFile->GetPath(mPath);
-    return NS_OK;
-  }
-
-  nsString mPath;
-};
-
-// We store the records in files in the system temp dir.
+// We store the records in files in the profile dir.
+// $profileDir/gmp/storage/$nodeId/
 static nsresult
-GetGMPStorageDir(nsIFile** aTempDir, const nsString& aOrigin)
+GetGMPStorageDir(nsIFile** aTempDir, const nsCString& aNodeId)
 {
   if (NS_WARN_IF(!aTempDir)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  // Directory service is main thread only...
-  nsRefPtr<GetTempDirTask> task = new GetTempDirTask();
-  nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-  mozilla::SyncRunnable::DispatchToThread(mainThread, task);
+  nsCOMPtr<mozIGeckoMediaPluginService> mps =
+    do_GetService("@mozilla.org/gecko-media-plugin-service;1");
+  if (NS_WARN_IF(!mps)) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsCOMPtr<nsIFile> tmpFile;
-  nsresult rv = NS_NewLocalFile(task->mPath, false, getter_AddRefs(tmpFile));
+  nsresult rv = mps->GetStorageDir(getter_AddRefs(tmpFile));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = tmpFile->AppendNative(nsDependentCString("mozilla-gmp-storage"));
+  rv = tmpFile->AppendNative(NS_LITERAL_CSTRING("storage"));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  // TODO: When aOrigin is the same node-id as the GMP sees in the child
-  // process (a UUID or somesuch), we can just append it un-hashed here.
-  // This should reduce the chance of hash collsions exposing data.
-  nsAutoString nodeIdHash;
-  nodeIdHash.AppendInt(HashString(static_cast<const char16_t*>(aOrigin.get())));
-  rv = tmpFile->Append(nodeIdHash);
+  rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
+  if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = tmpFile->AppendNative(aNodeId);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
   if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   tmpFile.forget(aTempDir);
 
   return NS_OK;
 }
 
-GMPStorageParent::GMPStorageParent(const nsString& aOrigin,
-                                   GMPParent* aPlugin)
-  : mOrigin(aOrigin)
-  , mPlugin(aPlugin)
-  , mShutdown(false)
-{
-}
-
 enum OpenFileMode  { ReadWrite, Truncate };
 
 nsresult
 OpenStorageFile(const nsCString& aRecordName,
-                const nsString& aNodeId,
+                const nsCString& aNodeId,
                 const OpenFileMode aMode,
                 PRFileDesc** aOutFD)
 {
   MOZ_ASSERT(aOutFD);
 
   nsCOMPtr<nsIFile> f;
   nsresult rv = GetGMPStorageDir(getter_AddRefs(f), aNodeId);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -129,159 +111,319 @@ OpenStorageFile(const nsCString& aRecord
   auto mode = PR_RDWR | PR_CREATE_FILE;
   if (aMode == Truncate) {
     mode |= PR_TRUNCATE;
   }
 
   return f->OpenNSPRFileDesc(mode, PR_IRWXU, aOutFD);
 }
 
+PLDHashOperator
+CloseFile(const nsACString& key, PRFileDesc*& entry, void* cx)
+{
+  if (PR_Close(entry) != PR_SUCCESS) {
+    NS_WARNING("GMPDiskStorage Failed to clsose file.");
+  }
+  return PL_DHASH_REMOVE;
+}
+
+class GMPDiskStorage : public GMPStorage {
+public:
+  GMPDiskStorage(const nsCString& aNodeId)
+    : mNodeId(aNodeId)
+  {
+  }
+  ~GMPDiskStorage() {
+    mFiles.Enumerate(CloseFile, nullptr);
+    MOZ_ASSERT(!mFiles.Count());
+  }
+
+  virtual GMPErr Open(const nsCString& aRecordName) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(!IsOpen(aRecordName));
+    PRFileDesc* fd = nullptr;
+    if (NS_FAILED(OpenStorageFile(aRecordName, mNodeId, ReadWrite, &fd))) {
+      NS_WARNING("Failed to open storage file.");
+      return GMPGenericErr;
+    }
+    mFiles.Put(aRecordName, fd);
+    return GMPNoErr;
+  }
+
+  virtual bool IsOpen(const nsCString& aRecordName) MOZ_OVERRIDE {
+    return mFiles.Contains(aRecordName);
+  }
+
+  virtual GMPErr Read(const nsCString& aRecordName,
+                      nsTArray<uint8_t>& aOutBytes) MOZ_OVERRIDE
+  {
+    PRFileDesc* fd = mFiles.Get(aRecordName);
+    if (!fd) {
+      return GMPGenericErr;
+    }
+
+    int32_t len = PR_Seek(fd, 0, PR_SEEK_END);
+    PR_Seek(fd, 0, PR_SEEK_SET);
+
+    if (len > GMP_MAX_RECORD_SIZE) {
+      // Refuse to read big records.
+      return GMPQuotaExceededErr;
+    }
+    aOutBytes.SetLength(len);
+    auto bytesRead = PR_Read(fd, aOutBytes.Elements(), len);
+    return (bytesRead == len) ? GMPNoErr : GMPGenericErr;
+  }
+
+  virtual GMPErr Write(const nsCString& aRecordName,
+                       const nsTArray<uint8_t>& aBytes) MOZ_OVERRIDE
+  {
+    PRFileDesc* fd = mFiles.Get(aRecordName);
+    if (!fd) {
+      return GMPGenericErr;
+    }
+
+    // Write operations overwrite the entire record. So re-open the file
+    // in truncate mode, to clear its contents.
+    PR_Close(fd);
+    mFiles.Remove(aRecordName);
+    if (NS_FAILED(OpenStorageFile(aRecordName, mNodeId, Truncate, &fd))) {
+      return GMPGenericErr;
+    }
+    mFiles.Put(aRecordName, fd);
+
+    int32_t bytesWritten = PR_Write(fd, aBytes.Elements(), aBytes.Length());
+    return (bytesWritten == (int32_t)aBytes.Length()) ? GMPNoErr : GMPGenericErr;
+  }
+
+  virtual void Close(const nsCString& aRecordName) MOZ_OVERRIDE
+  {
+    PRFileDesc* fd = mFiles.Get(aRecordName);
+    if (fd) {
+      if (PR_Close(fd) == PR_SUCCESS) {
+        mFiles.Remove(aRecordName);
+      } else {
+        NS_WARNING("GMPDiskStorage Failed to clsose file.");
+      }
+    }
+  }
+
+private:
+  nsDataHashtable<nsCStringHashKey, PRFileDesc*> mFiles;
+  const nsAutoCString mNodeId;
+};
+
+class GMPMemoryStorage : public GMPStorage {
+public:
+  virtual GMPErr Open(const nsCString& aRecordName) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(!IsOpen(aRecordName));
+
+    Record* record = nullptr;
+    if (!mRecords.Get(aRecordName, &record)) {
+      record = new Record();
+      mRecords.Put(aRecordName, record);
+    }
+    record->mIsOpen = true;
+    return GMPNoErr;
+  }
+
+  virtual bool IsOpen(const nsCString& aRecordName) MOZ_OVERRIDE {
+    Record* record = nullptr;
+    if (!mRecords.Get(aRecordName, &record)) {
+      return false;
+    }
+    return record->mIsOpen;
+  }
+
+  virtual GMPErr Read(const nsCString& aRecordName,
+                      nsTArray<uint8_t>& aOutBytes) MOZ_OVERRIDE
+  {
+    Record* record = nullptr;
+    if (!mRecords.Get(aRecordName, &record)) {
+      return GMPGenericErr;
+    }
+    aOutBytes = record->mData;
+    return GMPNoErr;
+  }
+
+  virtual GMPErr Write(const nsCString& aRecordName,
+                       const nsTArray<uint8_t>& aBytes) MOZ_OVERRIDE
+  {
+    Record* record = nullptr;
+    if (!mRecords.Get(aRecordName, &record)) {
+      return GMPClosedErr;
+    }
+    record->mData = aBytes;
+    return GMPNoErr;
+  }
+
+  virtual void Close(const nsCString& aRecordName) MOZ_OVERRIDE
+  {
+    Record* record = nullptr;
+    if (!mRecords.Get(aRecordName, &record)) {
+      return;
+    }
+    if (!record->mData.Length()) {
+      // Record is empty, delete.
+      mRecords.Remove(aRecordName);
+    } else {
+      record->mIsOpen = false;
+    }
+  }
+
+private:
+
+  struct Record {
+    Record() : mIsOpen(false) {}
+    nsTArray<uint8_t> mData;
+    bool mIsOpen;
+  };
+
+  nsClassHashtable<nsCStringHashKey, Record> mRecords;
+};
+
+GMPStorageParent::GMPStorageParent(const nsCString& aNodeId,
+                                   GMPParent* aPlugin)
+  : mNodeId(aNodeId)
+  , mPlugin(aPlugin)
+  , mShutdown(false)
+{
+}
+
+nsresult
+GMPStorageParent::Init()
+{
+  if (NS_WARN_IF(mNodeId.IsEmpty())) {
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr<mozIGeckoMediaPluginService> mps =
+    do_GetService("@mozilla.org/gecko-media-plugin-service;1");
+  if (NS_WARN_IF(!mps)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  bool persistent = false;
+  if (NS_WARN_IF(NS_FAILED(mps->IsPersistentStorageAllowed(mNodeId, &persistent)))) {
+    return NS_ERROR_FAILURE;
+  }
+  if (persistent) {
+    mStorage = MakeUnique<GMPDiskStorage>(mNodeId);
+  } else {
+    mStorage = MakeUnique<GMPMemoryStorage>();
+  }
+
+  return NS_OK;
+}
+
 bool
 GMPStorageParent::RecvOpen(const nsCString& aRecordName)
 {
   if (mShutdown) {
-    return true;
+    return false;
   }
 
-  if (mOrigin.EqualsASCII("null")) {
-    // Refuse to open storage if the page is the "null" origin; if the page
-    // is opened from disk.
-    NS_WARNING("Refusing to open storage for null origin");
+  if (mNodeId.EqualsLiteral("null")) {
+    // Refuse to open storage if the page is opened from local disk,
+    // or shared across origin.
+    NS_WARNING("Refusing to open storage for null NodeId");
     unused << SendOpenComplete(aRecordName, GMPGenericErr);
     return true;
   }
 
-  if (aRecordName.IsEmpty() || mFiles.Contains(aRecordName)) {
+  if (aRecordName.IsEmpty()) {
+    unused << SendOpenComplete(aRecordName, GMPGenericErr);
+    return true;
+  }
+
+  if (mStorage->IsOpen(aRecordName)) {
     unused << SendOpenComplete(aRecordName, GMPRecordInUse);
     return true;
   }
 
-  PRFileDesc* fd = nullptr;
-  nsresult rv = OpenStorageFile(aRecordName, mOrigin, ReadWrite, &fd);
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Failed to open storage file.");
-    unused << SendOpenComplete(aRecordName, GMPGenericErr);
-    return true;
-  }
-
-  mFiles.Put(aRecordName, fd);
-  unused << SendOpenComplete(aRecordName, GMPNoErr);
+  auto err = mStorage->Open(aRecordName);
+  MOZ_ASSERT(GMP_FAILED(err) || mStorage->IsOpen(aRecordName));
+  unused << SendOpenComplete(aRecordName, err);
 
   return true;
 }
 
 bool
 GMPStorageParent::RecvRead(const nsCString& aRecordName)
 {
   LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get()));
 
   if (mShutdown) {
-    return true;
-  }
-
-  PRFileDesc* fd = mFiles.Get(aRecordName);
-  nsTArray<uint8_t> data;
-  if (!fd) {
-    unused << SendReadComplete(aRecordName, GMPClosedErr, data);
-    return true;
+    return false;
   }
 
-  int32_t len = PR_Seek(fd, 0, PR_SEEK_END);
-  PR_Seek(fd, 0, PR_SEEK_SET);
-
-  if (len > GMP_MAX_RECORD_SIZE) {
-    // Refuse to read big records.
-    unused << SendReadComplete(aRecordName, GMPQuotaExceededErr, data);
-    return true;
+  nsTArray<uint8_t> data;
+  if (!mStorage->IsOpen(aRecordName)) {
+    unused << SendReadComplete(aRecordName, GMPClosedErr, data);
+  } else {
+    unused << SendReadComplete(aRecordName, mStorage->Read(aRecordName, data), data);
   }
-  data.SetLength(len);
-  auto bytesRead = PR_Read(fd, data.Elements(), len);
-  auto res = (bytesRead == len) ? GMPNoErr : GMPGenericErr;
-  unused << SendReadComplete(aRecordName, res, data);
 
   return true;
 }
 
 bool
 GMPStorageParent::RecvWrite(const nsCString& aRecordName,
                             const InfallibleTArray<uint8_t>& aBytes)
 {
   LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get()));
 
   if (mShutdown) {
+    return false;
+  }
+
+  if (!mStorage->IsOpen(aRecordName)) {
+    unused << SendWriteComplete(aRecordName, GMPClosedErr);
     return true;
   }
+
   if (aBytes.Length() > GMP_MAX_RECORD_SIZE) {
     unused << SendWriteComplete(aRecordName, GMPQuotaExceededErr);
     return true;
   }
 
-  PRFileDesc* fd = mFiles.Get(aRecordName);
-  if (!fd) {
-    unused << SendWriteComplete(aRecordName, GMPGenericErr);
-    return true;
-  }
+  unused << SendWriteComplete(aRecordName, mStorage->Write(aRecordName, aBytes));
 
-  // Write operations overwrite the entire record. So re-open the file
-  // in truncate mode, to clear its contents.
-  PR_Close(fd);
-  mFiles.Remove(aRecordName);
-  if (NS_FAILED(OpenStorageFile(aRecordName, mOrigin, Truncate, &fd))) {
-    unused << SendWriteComplete(aRecordName, GMPGenericErr);
-    return true;
-  }
-  mFiles.Put(aRecordName, fd);
-
-  int32_t bytesWritten = PR_Write(fd, aBytes.Elements(), aBytes.Length());
-  auto res = (bytesWritten == (int32_t)aBytes.Length()) ? GMPNoErr : GMPGenericErr;
-  unused << SendWriteComplete(aRecordName, res);
   return true;
 }
 
 bool
 GMPStorageParent::RecvClose(const nsCString& aRecordName)
 {
   LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get()));
 
   if (mShutdown) {
     return true;
   }
 
-  PRFileDesc* fd = mFiles.Get(aRecordName);
-  if (!fd) {
-    return true;
-  }
-  PR_Close(fd);
-  mFiles.Remove(aRecordName);
+  mStorage->Close(aRecordName);
+
   return true;
 }
 
 void
 GMPStorageParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
   Shutdown();
 }
 
-PLDHashOperator
-CloseFile(const nsACString& key, PRFileDesc*& entry, void* cx)
-{
-  PR_Close(entry);
-  return PL_DHASH_REMOVE;
-}
-
 void
 GMPStorageParent::Shutdown()
 {
   LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
 
   if (mShutdown) {
     return;
   }
   mShutdown = true;
   unused << SendShutdown();
 
-  mFiles.Enumerate(CloseFile, nullptr);
-  MOZ_ASSERT(!mFiles.Count());
+  mStorage = nullptr;
+
 }
 
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/GMPStorageParent.h
+++ b/content/media/gmp/GMPStorageParent.h
@@ -3,45 +3,59 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GMPStorageParent_h_
 #define GMPStorageParent_h_
 
 #include "mozilla/gmp/PGMPStorageParent.h"
 #include "gmp-storage.h"
-#include "nsTHashtable.h"
-#include "nsDataHashtable.h"
-#include "prio.h"
+#include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 namespace gmp {
 
 class GMPParent;
 
+class GMPStorage {
+public:
+  virtual ~GMPStorage() {}
+
+  virtual GMPErr Open(const nsCString& aRecordName) = 0;
+  virtual bool IsOpen(const nsCString& aRecordName) = 0;
+  virtual GMPErr Read(const nsCString& aRecordName,
+                      nsTArray<uint8_t>& aOutBytes) = 0;
+  virtual GMPErr Write(const nsCString& aRecordName,
+                       const nsTArray<uint8_t>& aBytes) = 0;
+  virtual void Close(const nsCString& aRecordName) = 0;
+};
+
 class GMPStorageParent : public PGMPStorageParent {
 public:
   NS_INLINE_DECL_REFCOUNTING(GMPStorageParent)
-  GMPStorageParent(const nsString& aOrigin, GMPParent* aPlugin);
+  GMPStorageParent(const nsCString& aNodeId,
+                   GMPParent* aPlugin);
 
+  nsresult Init();
   void Shutdown();
 
 protected:
   virtual bool RecvOpen(const nsCString& aRecordName) MOZ_OVERRIDE;
   virtual bool RecvRead(const nsCString& aRecordName) MOZ_OVERRIDE;
   virtual bool RecvWrite(const nsCString& aRecordName,
                          const InfallibleTArray<uint8_t>& aBytes) MOZ_OVERRIDE;
   virtual bool RecvClose(const nsCString& aRecordName) MOZ_OVERRIDE;
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
 private:
   ~GMPStorageParent() {}
 
-  nsDataHashtable<nsCStringHashKey, PRFileDesc*> mFiles;
-  const nsString mOrigin;
+  UniquePtr<GMPStorage> mStorage;
+
+  const nsCString mNodeId;
   nsRefPtr<GMPParent> mPlugin;
   bool mShutdown;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPStorageParent_h_
--- a/content/media/gmp/PGMP.ipdl
+++ b/content/media/gmp/PGMP.ipdl
@@ -35,14 +35,16 @@ parent:
   async AsyncShutdownRequired();
 
 child:
   async PGMPAudioDecoder();
   async PGMPDecryptor();
   async PGMPVideoDecoder();
   async PGMPVideoEncoder();
 
+  async SetNodeId(nsCString nodeId);
+  async StartPlugin();
   async BeginAsyncShutdown();
   async CrashPluginNow();
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/PGMPStorage.ipdl
+++ b/content/media/gmp/PGMPStorage.ipdl
@@ -1,34 +1,34 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-include protocol PGMP;
-include GMPTypes;
-
-using GMPErr from "gmp-errors.h";
-
-namespace mozilla {
-namespace gmp {
-
-async protocol PGMPStorage
-{
-  manager PGMP;
-
-child:
-  OpenComplete(nsCString aRecordName, GMPErr aStatus);
-  ReadComplete(nsCString aRecordName, GMPErr aStatus, uint8_t[] aBytes);
-  WriteComplete(nsCString aRecordName, GMPErr aStatus);
-  Shutdown();
-
-parent:
-  Open(nsCString aRecordName);
-  Read(nsCString aRecordName);
-  Write(nsCString aRecordName, uint8_t[] aBytes);
-  Close(nsCString aRecordName);
-  __delete__();
-
-};
-
-} // namespace gmp
-} // namespace mozilla
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PGMP;
+include GMPTypes;
+
+using GMPErr from "gmp-errors.h";
+
+namespace mozilla {
+namespace gmp {
+
+async protocol PGMPStorage
+{
+  manager PGMP;
+
+child:
+  OpenComplete(nsCString aRecordName, GMPErr aStatus);
+  ReadComplete(nsCString aRecordName, GMPErr aStatus, uint8_t[] aBytes);
+  WriteComplete(nsCString aRecordName, GMPErr aStatus);
+  Shutdown();
+
+parent:
+  Open(nsCString aRecordName);
+  Read(nsCString aRecordName);
+  Write(nsCString aRecordName, uint8_t[] aBytes);
+  Close(nsCString aRecordName);
+  __delete__();
+
+};
+
+} // namespace gmp
+} // namespace mozilla
--- a/content/media/gmp/moz.build
+++ b/content/media/gmp/moz.build
@@ -85,16 +85,21 @@ UNIFIED_SOURCES += [
     'GMPVideoEncodedFrameImpl.cpp',
     'GMPVideoEncoderChild.cpp',
     'GMPVideoEncoderParent.cpp',
     'GMPVideoHost.cpp',
     'GMPVideoi420FrameImpl.cpp',
     'GMPVideoPlaneImpl.cpp',
 ]
 
+if CONFIG['OS_TARGET'] == 'WINNT':
+  DIRS += [
+      'rlz',
+  ]
+
 IPDL_SOURCES += [
   'GMPTypes.ipdlh',
   'PGMP.ipdl',
   'PGMPAudioDecoder.ipdl',
   'PGMPDecryptor.ipdl',
   'PGMPStorage.ipdl',
   'PGMPTimer.ipdl',
   'PGMPVideoDecoder.ipdl',
--- a/content/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/content/media/gmp/mozIGeckoMediaPluginService.idl
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "nsISupports.idl"
 #include "nsIThread.idl"
 #include "nsIPrincipal.idl"
+#include "nsIFile.idl"
 
 %{C++
 #include "nsTArray.h"
 #include "nsStringGlue.h"
 class GMPAudioDecoderProxy;
 class GMPDecryptorProxy;
 class GMPVideoDecoderProxy;
 class GMPVideoEncoderProxy;
@@ -20,72 +21,93 @@ class GMPVideoHost;
 [ptr] native GMPVideoDecoderProxy(GMPVideoDecoderProxy);
 [ptr] native GMPVideoEncoderProxy(GMPVideoEncoderProxy);
 [ptr] native GMPVideoHost(GMPVideoHost);
 [ptr] native MessageLoop(MessageLoop);
 [ptr] native TagArray(nsTArray<nsCString>);
 [ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
 [ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
 
-[scriptable, uuid(6ea374fc-32ad-46f6-ae9d-80b668f4fd49)]
+[scriptable, uuid(b350d3b6-00c9-4602-bdfe-84c2be8d1e7a)]
 interface mozIGeckoMediaPluginService : nsISupports
 {
+
   /**
    * The GMP thread. Callable from any thread.
    */
   readonly attribute nsIThread thread;
 
   /**
    * Get a plugin that supports the specified tags.
    * Callable on any thread
    */
   [noscript]
-  boolean hasPluginForAPI([optional] in AString origin,
+  boolean hasPluginForAPI([optional] in ACString nodeId,
                           in ACString api,
                           in TagArray tags);
 
   /**
    * Get a video decoder that supports the specified tags.
    * The array of tags should at least contain a codec tag, and optionally
    * other tags such as for EME keysystem.
    * Callable only on GMP thread.
    */
   [noscript]
   GMPVideoDecoderProxy getGMPVideoDecoder(in TagArray tags,
-                                          [optional] in AString origin,
+                                          [optional] in ACString nodeId,
                                           out GMPVideoHost outVideoHost);
 
   /**
    * Get a video encoder that supports the specified tags.
    * The array of tags should at least contain a codec tag, and optionally
    * other tags.
    * Callable only on GMP thread.
    */
   [noscript]
   GMPVideoEncoderProxy getGMPVideoEncoder(in TagArray tags,
-		                                      [optional] in AString origin,
+		                                      [optional] in ACString nodeId,
 		                                      out GMPVideoHost outVideoHost);
 
   // Returns an audio decoder that supports the specified tags.
   // The array of tags should at least contain a codec tag, and optionally
   // other tags such as for EME keysystem.
   // Callable only on GMP thread.
   GMPAudioDecoderProxy getGMPAudioDecoder(in TagArray tags,
-                                          [optional] in AString origin);
+                                          [optional] in ACString nodeId);
 
   // Returns a decryption session manager that supports the specified tags.
   // The array of tags should at least contain a key system tag, and optionally
   // other tags.
   // Callable only on GMP thread.
-  GMPDecryptorProxy getGMPDecryptor(in TagArray tags, in AString origin);
+  GMPDecryptorProxy getGMPDecryptor(in TagArray tags, in ACString nodeId);
 
   /**
    * Add a directory to scan for gecko media plugins.
    * @note Main-thread API.
    */
   void addPluginDirectory(in AString directory);
 
   /**
    * Remove a directory for gecko media plugins.
    * @note Main-thread API.
    */
   void removePluginDirectory(in AString directory);
+
+  /**
+   * Gets the NodeId for a (origin, urlbarOrigin, isInprivateBrowsing) tuple.
+   */
+  ACString getNodeId(in AString origin,
+                     in AString topLevelOrigin,
+                     in bool inPrivateBrowsingMode);
+
+  /**
+   * Returns true if the given node id is allowed to store things
+   * persistently on disk. Private Browsing and local content are not
+   * allowed to store persistent data.
+   */
+  bool isPersistentStorageAllowed(in ACString nodeId);
+
+  /**
+   * Returns the directory to use as the base for storing data about GMPs.
+   */
+  nsIFile getStorageDir();
+
 };
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/COPYING
@@ -0,0 +1,14 @@
+Copyright 2010 Google Inc.
+
+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.
+
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/README.mozilla
@@ -0,0 +1,6 @@
+Code taken from rlz project: https://code.google.com/p/rlz/
+
+Revision: 134, then with unused code stripped out.
+
+Note: base/ contains wrappers/dummies to provide implementations of the
+Chromium APIs that this code relies upon.
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/base/memory/scoped_ptr.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+// The scoped_ptr.h our IPC copy of Chromium's code does not include
+// scoped_array, so adapt it to nsAutoArrayPtr here.
+
+#ifndef FAKE_SCOPED_PTR_H_
+#define FAKE_SCOPED_PTR_H_
+
+#include "mozilla/ArrayUtils.h"
+#include "nsAutoPtr.h"
+
+template<class T>
+class scoped_array : public nsAutoArrayPtr<T> {
+public:
+  scoped_array(T* t) : nsAutoArrayPtr<T>(t) {}
+  void reset(T* t) {
+    scoped_array<T> other(t);
+    operator=(other);
+  }
+};
+
+#define arraysize mozilla::ArrayLength
+
+#endif
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/base/string16.h
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef FAKE_STRING16_H
+#define FAKE_STRING16_H
+
+#include <string>
+typedef std::wstring string16;
+
+#endif
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/lib/assert.h
@@ -0,0 +1,14 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef FAKE_ASSERT_H_
+#define FAKE_ASSERT_H_
+
+#include <assert.h>
+
+#define ASSERT_STRING(x) { assert(false); }
+#define VERIFY(x) { assert(x); };
+
+#endif
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/lib/machine_id.h
@@ -0,0 +1,21 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+// Use of this source code is governed by an Apache-style license that can be
+// found in the COPYING file.
+
+#ifndef RLZ_LIB_MACHINE_ID_H_
+#define RLZ_LIB_MACHINE_ID_H_
+
+#include "base/string16.h"
+
+#include <string>
+
+namespace rlz_lib {
+
+// Retrieves a raw machine identifier string and a machine-specific
+// 4 byte value. GetMachineId() will SHA1 |data|, append |more_data|, compute
+// the Crc8 of that, and return a hex-encoded string of that data.
+bool GetRawMachineId(string16* data, int* more_data);
+
+}  // namespace rlz_lib
+
+#endif  // RLZ_LIB_MACHINE_ID_H_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/lib/string_utils.cc
@@ -0,0 +1,34 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+// Use of this source code is governed by an Apache-style license that can be
+// found in the COPYING file.
+//
+// String manipulation functions used in the RLZ library.
+
+#include "rlz/lib/string_utils.h"
+
+namespace rlz_lib {
+
+bool BytesToString(const unsigned char* data,
+                   int data_len,
+                   std::string* string) {
+  if (!string)
+    return false;
+
+  string->clear();
+  if (data_len < 1 || !data)
+    return false;
+
+  static const char kHex[] = "0123456789ABCDEF";
+
+  // Fix the buffer size to begin with to avoid repeated re-allocation.
+  string->resize(data_len * 2);
+  int index = data_len;
+  while (index--) {
+    string->at(2 * index) = kHex[data[index] >> 4];  // high digit
+    string->at(2 * index + 1) = kHex[data[index] & 0x0F];  // low digit
+  }
+
+  return true;
+}
+
+}  // namespace rlz_lib
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/lib/string_utils.h
@@ -0,0 +1,20 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+// Use of this source code is governed by an Apache-style license that can be
+// found in the COPYING file.
+//
+// String manipulation functions used in the RLZ library.
+
+#ifndef RLZ_LIB_STRING_UTILS_H_
+#define RLZ_LIB_STRING_UTILS_H_
+
+#include <string>
+
+namespace rlz_lib {
+
+bool BytesToString(const unsigned char* data,
+                   int data_len,
+                   std::string* string);
+
+};  // namespace
+
+#endif  // RLZ_LIB_STRING_UTILS_H_
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/moz.build
@@ -0,0 +1,20 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+# Note: build rlz in its own moz.build, so it doesn't pickup any of
+# Chromium IPC's headers used in the moz.build of the parent file.
+
+UNIFIED_SOURCES += [
+    'lib/string_utils.cc',
+    'win/lib/machine_id_win.cc',
+]
+
+FINAL_LIBRARY = 'xul'
+FAIL_ON_WARNINGS = True
+
+LOCAL_INCLUDES += [
+    '..',
+]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/content/media/gmp/rlz/win/lib/machine_id_win.cc
@@ -0,0 +1,131 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+// Use of this source code is governed by an Apache-style license that can be
+// found in the COPYING file.
+
+#include <windows.h>
+#include <Sddl.h>  // For ConvertSidToStringSidW.
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/string16.h"
+#include "rlz/lib/assert.h"
+
+namespace rlz_lib {
+
+namespace {
+
+bool GetSystemVolumeSerialNumber(int* number) {
+  if (!number)
+    return false;
+
+  *number = 0;
+
+  // Find the system root path (e.g: C:\).
+  wchar_t system_path[MAX_PATH + 1];
+  if (!GetSystemDirectoryW(system_path, MAX_PATH))
+    return false;
+
+  wchar_t* first_slash = wcspbrk(system_path, L"\\/");
+  if (first_slash != NULL)
+    *(first_slash + 1) = 0;
+
+  DWORD number_local = 0;
+  if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL,
+                             NULL, 0))
+    return false;
+
+  *number = (int)number_local;
+  return true;
+}
+
+bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) {
+  static const DWORD kStartDomainLength = 128;  // reasonable to start with
+
+  scoped_array<wchar_t> domain_buffer(new wchar_t[kStartDomainLength]);
+  DWORD domain_size = kStartDomainLength;
+  DWORD sid_dword_size = sid_size;
+  SID_NAME_USE sid_name_use;
+
+  BOOL success = ::LookupAccountNameW(NULL, account_name, sid,
+                                      &sid_dword_size, domain_buffer.get(),
+                                      &domain_size, &sid_name_use);
+  if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+    // We could have gotten the insufficient buffer error because
+    // one or both of sid and szDomain was too small. Check for that
+    // here.
+    if (sid_dword_size > sid_size)
+      return false;
+
+    if (domain_size > kStartDomainLength)
+      domain_buffer.reset(new wchar_t[domain_size]);
+
+    success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size,
+                                   domain_buffer.get(), &domain_size,
+                                   &sid_name_use);
+  }
+
+  return success != FALSE;
+}
+
+std::wstring ConvertSidToString(SID* sid) {
+  std::wstring sid_string;
+#if _WIN32_WINNT >= 0x500
+  wchar_t* sid_buffer = NULL;
+  if (ConvertSidToStringSidW(sid, &sid_buffer)) {
+    sid_string = sid_buffer;
+    LocalFree(sid_buffer);
+  }
+#else
+  SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid);
+
+  if(sia->Value[0] || sia->Value[1]) {
+    base::SStringPrintf(
+        &sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx",
+        SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1],
+        (USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4],
+        (USHORT)sia->Value[5]);
+  } else {
+    ULONG authority = 0;
+    for (int i = 2; i < 6; ++i) {
+      authority <<= 8;
+      authority |= sia->Value[i];
+    }
+    base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority);
+  }
+
+  int sub_auth_count = *::GetSidSubAuthorityCount(sid);
+  for(int i = 0; i < sub_auth_count; ++i)
+    base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i));
+#endif
+
+  return sid_string;
+}
+
+}  // namespace
+
+bool GetRawMachineId(string16* sid_string, int* volume_id) {
+  // Calculate the Windows SID.
+
+  wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0};
+  DWORD size = arraysize(computer_name);
+
+  if (!GetComputerNameW(computer_name, &size)) {
+    return false;
+  }
+  char sid_buffer[SECURITY_MAX_SID_SIZE];
+  SID* sid = reinterpret_cast<SID*>(sid_buffer);
+  if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) {
+    *sid_string = ConvertSidToString(sid);
+  }
+
+  // Get the system drive volume serial number.
+  *volume_id = 0;
+  if (!GetSystemVolumeSerialNumber(volume_id)) {
+    ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number");
+    *volume_id = 0;
+  }
+
+  return true;
+}
+
+}  // namespace rlz_lib
--- a/content/media/ogg/OggCodecState.cpp
+++ b/content/media/ogg/OggCodecState.cpp
@@ -292,17 +292,17 @@ bool
 TheoraState::DecodeHeader(ogg_packet* aPacket)
 {
   nsAutoRef<ogg_packet> autoRelease(aPacket);
   mPacketCount++;
   int ret = th_decode_headerin(&mInfo,
                                &mComment,
                                &mSetup,
                                aPacket);
- 
+
   // We must determine when we've read the last header packet.
   // th_decode_headerin() does not tell us when it's read the last header, so
   // we must keep track of the headers externally.
   //
   // There are 3 header packets, the Identification, Comment, and Setup
   // headers, which must be in that order. If they're out of order, the file
   // is invalid. If we've successfully read a header, and it's the setup
   // header, then we're done reading headers. The first byte of each packet
@@ -345,17 +345,17 @@ TheoraState::IsHeader(ogg_packet* aPacke
 
 int64_t TheoraState::Time(th_info* aInfo, int64_t aGranulepos)
 {
   if (aGranulepos < 0 || aInfo->fps_numerator == 0) {
     return -1;
   }
   // Implementation of th_granule_frame inlined here to operate
   // on the th_info structure instead of the theora_state.
-  int shift = aInfo->keyframe_granule_shift; 
+  int shift = aInfo->keyframe_granule_shift;
   ogg_int64_t iframe = aGranulepos >> shift;
   ogg_int64_t pframe = aGranulepos - (iframe << shift);
   int64_t frameno = iframe + pframe - TH_VERSION_CHECK(aInfo, 3, 2, 1);
   CheckedInt64 t = ((CheckedInt64(frameno) + 1) * USECS_PER_S) * aInfo->fps_denominator;
   if (!t.isValid())
     return -1;
   t /= aInfo->fps_numerator;
   return t.isValid() ? t.value() : -1;
@@ -375,17 +375,17 @@ int64_t
 TheoraState::MaxKeyframeOffset()
 {
   // Determine the maximum time in microseconds by which a key frame could
   // offset for the theora bitstream. Theora granulepos encode time as:
   // ((key_frame_number << granule_shift) + frame_offset).
   // Therefore the maximum possible time by which any frame could be offset
   // from a keyframe is the duration of (1 << granule_shift) - 1) frames.
   int64_t frameDuration;
-  
+
   // Max number of frames keyframe could possibly be offset.
   int64_t keyframeDiff = (1 << mInfo.keyframe_granule_shift) - 1;
 
   // Length of frame in usecs.
   frameDuration = (mInfo.fps_denominator * USECS_PER_S) / mInfo.fps_numerator;
 
   // Total time in usecs keyframe can be offset from any given frame.
   return frameDuration * keyframeDiff;
@@ -487,17 +487,17 @@ void TheoraState::ReconstructTheoraGranu
       // granulepos, so we take "keyframe" to be the max possible offset
       // frame instead.
       ogg_int64_t k = std::max(frame - (((ogg_int64_t)1 << shift) - 1), version_3_2_1);
       granulepos = (k << shift) + (frame - k);
     }
     // Theora 3.2.1+ granulepos store frame number [1..N], so granulepos
     // should be > 0.
     // Theora 3.2.0 granulepos store the frame index [0..(N-1)], so
-    // granulepos should be >= 0. 
+    // granulepos should be >= 0.
     NS_ASSERTION(granulepos >= version_3_2_1,
                   "Invalid granulepos for Theora version");
 
     // Check that the frame's granule number is one more than the
     // previous frame's.
     NS_ASSERTION(i == 0 ||
                  th_granule_frame(mCtx, granulepos) ==
                  th_granule_frame(mCtx, mUnstamped[i-1]->granulepos) + 1,
@@ -719,17 +719,17 @@ nsresult VorbisState::ReconstructVorbisG
     if (packet->granulepos == -1) {
       packet->granulepos = mGranulepos + samples;
     }
 
     // Account for a partial last frame
     if (packet->e_o_s && packet->granulepos >= mGranulepos) {
        samples = packet->granulepos - mGranulepos;
     }
- 
+
     mGranulepos = packet->granulepos;
     RecordVorbisPacketSamples(packet, samples);
     return NS_OK;
   }
 
   bool unknownGranulepos = last->granulepos == -1;
   int totalSamples = 0;
   for (int32_t i = mUnstamped.Length() - 1; i > 0; i--) {
@@ -1083,17 +1083,17 @@ bool OpusState::ReconstructOpusGranulepo
 SkeletonState::SkeletonState(ogg_page* aBosPage) :
   OggCodecState(aBosPage, true),
   mVersion(0),
   mPresentationTime(0),
   mLength(0)
 {
   MOZ_COUNT_CTOR(SkeletonState);
 }
- 
+
 SkeletonState::~SkeletonState()
 {
   MOZ_COUNT_DTOR(SkeletonState);
 }
 
 // Support for Ogg Skeleton 4.0, as per specification at:
 // http://wiki.xiph.org/Ogg_Skeleton_4
 
@@ -1218,38 +1218,38 @@ bool SkeletonState::DecodeIndex(ogg_pack
 
   // Check the numKeyPoints value read, ensure we're not going to run out of
   // memory while trying to decode the index packet.
   CheckedInt64 minPacketSize = (CheckedInt64(numKeyPoints) * MIN_KEY_POINT_SIZE) + INDEX_KEYPOINT_OFFSET;
   if (!minPacketSize.isValid())
   {
     return (mActive = false);
   }
-  
+
   int64_t sizeofIndex = aPacket->bytes - INDEX_KEYPOINT_OFFSET;
   int64_t maxNumKeyPoints = sizeofIndex / MIN_KEY_POINT_SIZE;
   if (aPacket->bytes < minPacketSize.value() ||
-      numKeyPoints > maxNumKeyPoints || 
+      numKeyPoints > maxNumKeyPoints ||
       numKeyPoints < 0)
   {
     // Packet size is less than the theoretical minimum size, or the packet is
     // claiming to store more keypoints than it's capable of storing. This means
     // that the numKeyPoints field is too large or small for the packet to
     // possibly contain as many packets as it claims to, so the numKeyPoints
     // field is possibly malicious. Don't try decoding this index, we may run
     // out of memory.
     LOG(PR_LOG_DEBUG, ("Possibly malicious number of key points reported "
                        "(%lld) in index packet for stream %u.",
                        numKeyPoints,
                        serialno));
     return (mActive = false);
   }
 
   nsAutoPtr<nsKeyFrameIndex> keyPoints(new nsKeyFrameIndex(startTime, endTime));
-  
+
   p = aPacket->packet + INDEX_KEYPOINT_OFFSET;
   const unsigned char* limit = aPacket->packet + aPacket->bytes;
   int64_t numKeyPointsRead = 0;
   CheckedInt64 offset = 0;
   CheckedInt64 time = 0;
   while (p < limit &&
          numKeyPointsRead < numKeyPoints)
   {
--- a/content/media/raw/RawReader.cpp
+++ b/content/media/raw/RawReader.cpp
@@ -60,17 +60,17 @@ nsresult RawReader::ReadMetadata(MediaIn
                           static_cast<uint32_t>(mMetadata.frameHeight);
   NS_ENSURE_TRUE(dummy.isValid(), NS_ERROR_FAILURE);
 
   if (mMetadata.aspectDenominator == 0 ||
       mMetadata.framerateDenominator == 0)
     return NS_ERROR_FAILURE; // Invalid data
 
   // Determine and verify frame display size.
-  float pixelAspectRatio = static_cast<float>(mMetadata.aspectNumerator) / 
+  float pixelAspectRatio = static_cast<float>(mMetadata.aspectNumerator) /
                             mMetadata.aspectDenominator;
   nsIntSize display(mMetadata.frameWidth, mMetadata.frameHeight);
   ScaleDisplayByAspectRatio(display, pixelAspectRatio);
   mPicture = nsIntRect(0, 0, mMetadata.frameWidth, mMetadata.frameHeight);
   nsIntSize frameSize(mMetadata.frameWidth, mMetadata.frameHeight);
   if (!IsValidVideoRegion(frameSize, mPicture, display)) {
     // Video track's frame sizes will overflow. Fail.
     return NS_ERROR_FAILURE;
@@ -121,17 +121,17 @@ RawReader::IsMediaSeekable()
 
  bool RawReader::DecodeAudioData()
 {
   NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
                "Should be on state machine thread or decode thread.");
   return false;
 }
 
-// Helper method that either reads until it gets aLength bytes 
+// Helper method that either reads until it gets aLength bytes
 // or returns false
 bool RawReader::ReadFromResource(MediaResource *aResource, uint8_t* aBuf,
                                    uint32_t aLength)
 {
   while (aLength > 0) {
     uint32_t bytesRead = 0;
     nsresult rv;
 
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -345,17 +345,17 @@ skip-if = toolkit == 'gonk' && debug
 [test_controls.html]
 [test_currentTime.html]
 [test_decode_error.html]
 [test_decoder_disable.html]
 [test_defaultMuted.html]
 [test_delay_load.html]
 skip-if = buildapp == 'b2g' # bug 1021676
 [test_encryptedMediaExtensions.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' # bug 1043403
+skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
 [test_error_in_video_document.html]
 skip-if = toolkit == 'android' # bug 608634
 [test_error_on_404.html]
 [test_fastSeek.html]
 [test_fastSeek-forwards.html]
 [test_imagecapture.html]
 [test_info_leak.html]
 [test_invalid_reject.html]
--- a/content/media/wave/WaveReader.cpp
+++ b/content/media/wave/WaveReader.cpp
@@ -260,17 +260,17 @@ bool WaveReader::DecodeVideoFrame(bool &
 nsresult WaveReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
   LOG(PR_LOG_DEBUG, ("%p About to seek to %lld", mDecoder, aTarget));
   if (NS_FAILED(ResetDecode())) {
     return NS_ERROR_FAILURE;
   }
   double d = BytesToTime(GetDataLength());
-  NS_ASSERTION(d < INT64_MAX / USECS_PER_S, "Duration overflow"); 
+  NS_ASSERTION(d < INT64_MAX / USECS_PER_S, "Duration overflow");
   int64_t duration = static_cast<int64_t>(d * USECS_PER_S);
   double seekTime = std::min(aTarget, duration) / static_cast<double>(USECS_PER_S);
   int64_t position = RoundDownToFrame(static_cast<int64_t>(TimeToBytes(seekTime)));
   NS_ASSERTION(INT64_MAX - mWavePCMOffset > position, "Integer overflow during wave seek");
   position += mWavePCMOffset;
   return mDecoder->GetResource()->Seek(nsISeekableStream::NS_SEEK_SET, position);
 }
 
@@ -286,17 +286,17 @@ nsresult WaveReader::GetBuffered(dom::Ti
   int64_t startOffset = mDecoder->GetResource()->GetNextCachedData(mWavePCMOffset);
   while (startOffset >= 0) {
     int64_t endOffset = mDecoder->GetResource()->GetCachedDataEnd(startOffset);
     // Bytes [startOffset..endOffset] are cached.
     NS_ASSERTION(startOffset >= mWavePCMOffset, "Integer underflow in GetBuffered");
     NS_ASSERTION(endOffset >= mWavePCMOffset, "Integer underflow in GetBuffered");
 
     // We need to round the buffered ranges' times to microseconds so that they
-    // have the same precision as the currentTime and duration attribute on 
+    // have the same precision as the currentTime and duration attribute on
     // the media element.
     aBuffered->Add(RoundToUsecs(BytesToTime(startOffset - mWavePCMOffset)),
                    RoundToUsecs(BytesToTime(endOffset - mWavePCMOffset)));
     startOffset = mDecoder->GetResource()->GetNextCachedData(endOffset);
   }
   return NS_OK;
 }
 
--- a/content/media/webm/WebMReader.h
+++ b/content/media/webm/WebMReader.h
@@ -66,39 +66,39 @@ class PacketQueueDeallocator : public ns
 // Typesafe queue for holding nestegg packets. It has
 // ownership of the items in the queue and will free them
 // when destroyed.
 class WebMPacketQueue : private nsDeque {
  public:
    WebMPacketQueue()
      : nsDeque(new PacketQueueDeallocator())
    {}
-  
+
   ~WebMPacketQueue() {
     Reset();
   }
 
-  inline int32_t GetSize() { 
+  inline int32_t GetSize() {
     return nsDeque::GetSize();
   }
-  
+
   inline void Push(NesteggPacketHolder* aItem) {
     NS_ASSERTION(aItem, "NULL pushed to WebMPacketQueue");
     nsDeque::Push(aItem);
   }
-  
+
   inline void PushFront(NesteggPacketHolder* aItem) {
     NS_ASSERTION(aItem, "NULL pushed to WebMPacketQueue");
     nsDeque::PushFront(aItem);
   }
 
   inline NesteggPacketHolder* PopFront() {
     return static_cast<NesteggPacketHolder*>(nsDeque::PopFront());
   }
-  
+
   void Reset() {
     while (GetSize() > 0) {
       delete PopFront();
     }
   }
 };
 
 class WebMReader : public MediaDecoderReader
@@ -111,17 +111,17 @@ protected:
 
 public:
   virtual nsresult Init(MediaDecoderReader* aCloneDonor);
   virtual nsresult ResetDecode();
   virtual bool DecodeAudioData();
 
   // If the Theora granulepos has not been captured, it may read several packets
   // until one with a granulepos has been captured, to ensure that all packets
-  // read have valid time info.  
+  // read have valid time info.
   virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
                                   int64_t aTimeThreshold);
 
   virtual bool HasAudio()
   {
     NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
     return mHasAudio;
   }
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/DOMException.h"
 
 #include "jsprf.h"
-#include "js/OldDebugAPI.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/dom/Exceptions.h"
 #include "nsContentUtils.h"
 #include "nsCOMPtr.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIDocument.h"
 #include "nsIDOMDOMException.h"
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -40,17 +40,16 @@
 #include "nsWindowMemoryReporter.h"
 #include "WindowNamedPropertiesHandler.h"
 #include "nsFrameSelection.h"
 #include "nsISelectionListener.h"
 
 // Helper Classes
 #include "nsJSUtils.h"
 #include "jsapi.h"              // for JSAutoRequest
-#include "js/OldDebugAPI.h"     // for JS_ClearWatchPointsForObject
 #include "jswrapper.h"
 #include "nsReadableUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsJSEnvironment.h"
 #include "ScriptSettings.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Likely.h"
 #include "mozilla/unused.h"
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -38,17 +38,17 @@
 #include "nsNetUtil.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsIXULRuntime.h"
 #include "nsTextFormatter.h"
 #include "ScriptSettings.h"
 
 #include "xpcpublic.h"
 
-#include "js/OldDebugAPI.h"
+#include "jsapi.h"
 #include "jswrapper.h"
 #include "nsIArray.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "prmem.h"
 #include "WrapperFactory.h"
 #include "nsGlobalWindow.h"
 #include "nsScriptNameSpaceManager.h"
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -8,17 +8,16 @@
  * This is not a generated file. It contains common utility functions
  * invoked from the JavaScript code generated from IDL interfaces.
  * The goal of the utility functions is to cut down on the size of
  * the generated code itself.
  */
 
 #include "nsJSUtils.h"
 #include "jsapi.h"
-#include "js/OldDebugAPI.h"
 #include "jsfriendapi.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIXPConnect.h"
 #include "nsCOMPtr.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsPIDOMWindow.h"
 #include "GeckoProfiler.h"
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -13,17 +13,16 @@
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Preferences.h"
 
 #include "AccessCheck.h"
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsIDOMGlobalPropertyInitializer.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIXPConnect.h"
 #include "nsUTF8Utils.h"
 #include "WrapperFactory.h"
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/Exceptions.h"
 
 #include "js/GCAPI.h"
-#include "js/OldDebugAPI.h"
 #include "jsapi.h"
 #include "jsprf.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
--- a/dom/json/nsJSON.cpp
+++ b/dom/json/nsJSON.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 sw=2 et tw=79: */
 /* 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 "jsapi.h"
 #include "js/CharacterEncoding.h"
-#include "js/OldDebugAPI.h"
 #include "nsJSON.h"
 #include "nsIXPConnect.h"
 #include "nsIXPCScriptable.h"
 #include "nsStreamUtils.h"
 #include "nsIInputStream.h"
 #include "nsStringStream.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsIUnicodeEncoder.h"
--- a/dom/promise/PromiseCallback.cpp
+++ b/dom/promise/PromiseCallback.cpp
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PromiseCallback.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 
-#include "js/OldDebugAPI.h"
+#include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PromiseCallback)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PromiseCallback)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PromiseCallback)
--- a/dom/workers/RegisterBindings.cpp
+++ b/dom/workers/RegisterBindings.cpp
@@ -3,17 +3,16 @@
  * 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 "WorkerPrivate.h"
 #include "ChromeWorkerScope.h"
 #include "RuntimeService.h"
 
 #include "jsapi.h"
-#include "js/OldDebugAPI.h"
 #include "mozilla/dom/RegisterWorkerBindings.h"
 #include "mozilla/OSFileConstants.h"
 
 USING_WORKERS_NAMESPACE
 using namespace mozilla::dom;
 
 bool
 WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -18,17 +18,16 @@
 #include "nsISupportsPriority.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsPIDOMWindow.h"
 
 #include <algorithm>
 #include "BackgroundChild.h"
 #include "GeckoProfiler.h"
-#include "js/OldDebugAPI.h"
 #include "jsfriendapi.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -26,17 +26,16 @@
 #include "nsIThreadInternal.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIXPConnect.h"
 
 #include <algorithm>
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Likely.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/BlobBinding.h"
--- a/dom/xbl/nsXBLSerialize.cpp
+++ b/dom/xbl/nsXBLSerialize.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "nsXBLSerialize.h"
 
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsIXPConnect.h"
 #include "nsContentUtils.h"
 
 using namespace mozilla;
 
 nsresult
 XBL_SerializeFunction(nsIObjectOutputStream* aStream,
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -10,17 +10,16 @@
 #endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>     /* for isatty() */
 #endif
 
 #include "base/basictypes.h"
 
 #include "jsapi.h"
-#include "js/OldDebugAPI.h"
 
 #include "xpcpublic.h"
 
 #include "XPCShellEnvironment.h"
 
 #include "mozilla/XPCOM.h"
 
 #include "nsIChannel.h"
--- a/js/ductwork/debugger/JSDebugger.cpp
+++ b/js/ductwork/debugger/JSDebugger.cpp
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "JSDebugger.h"
 #include "nsIXPConnect.h"
 #include "nsThreadUtils.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jswrapper.h"
-#include "js/OldDebugAPI.h"
 #include "mozilla/ModuleUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsMemory.h"
 
 #define JSDEBUGGER_CONTRACTID \
   "@mozilla.org/jsdebugger;1"
 
 #define JSDEBUGGER_CID \
--- a/js/ipc/JavaScriptLogging.h
+++ b/js/ipc/JavaScriptLogging.h
@@ -6,17 +6,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_jsipc_JavaScriptLogging__
 #define mozilla_jsipc_JavaScriptLogging__
 
 #include "nsString.h"
 #include "nsPrintfCString.h"
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 
 namespace mozilla {
 namespace jsipc {
 
 #define LOG(...)						               \
     PR_BEGIN_MACRO                                                             \
     if (LoggingEnabled()) {                                                    \
 	Logging log(this, cx);					               \
deleted file mode 100644
--- a/js/public/OldDebugAPI.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef js_OldDebugAPI_h
-#define js_OldDebugAPI_h
-
-/*
- * JS debugger API.
- */
-
-#include "mozilla/NullPtr.h"
-
-#include "jsapi.h"
-#include "jsbytecode.h"
-
-#include "js/CallArgs.h"
-#include "js/TypeDecls.h"
-
-typedef enum JSTrapStatus {
-    JSTRAP_ERROR,
-    JSTRAP_CONTINUE,
-    JSTRAP_RETURN,
-    JSTRAP_THROW,
-    JSTRAP_LIMIT
-} JSTrapStatus;
-
-/************************************************************************/
-
-extern JS_PUBLIC_API(JSScript *)
-JS_GetFunctionScript(JSContext *cx, JS::HandleFunction fun);
-
-/************************************************************************/
-
-extern JS_PUBLIC_API(const char *)
-JS_GetScriptFilename(JSScript *script);
-
-extern JS_PUBLIC_API(unsigned)
-JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script);
-
-#endif /* js_OldDebugAPI_h */
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -70,24 +70,17 @@ EvalCacheHashPolicy::match(const EvalCac
     JSAtom *keyStr = script->atoms[0];
 
     return EqualStrings(keyStr, l.str) &&
            cacheEntry.callerScript == l.callerScript &&
            script->getVersion() == l.version &&
            cacheEntry.pc == l.pc;
 }
 
-// There are two things we want to do with each script executed in EvalKernel:
-//  1. notify OldDebugAPI about script creation/destruction
-//  2. add the script to the eval cache when EvalKernel is finished
-//
-// NB: Although the eval cache keeps a script alive wrt to the JS engine, from
-// an OldDebugAPI  user's perspective, we want each eval() to create and
-// destroy a script. This hides implementation details and means we don't have
-// to deal with calls to JS_GetScriptObject for scripts in the eval cache.
+// Add the script to the eval cache when EvalKernel is finished
 class EvalScriptGuard
 {
     JSContext *cx_;
     Rooted<JSScript*> script_;
 
     /* These fields are only valid if lookup_.str is non-nullptr. */
     EvalCacheLookup lookup_;
     EvalCache::AddPtr p_;
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -87,17 +87,17 @@ LBlock::init(TempAllocator &alloc)
     size_t numLPhis = 0;
     for (MPhiIterator i(block_->phisBegin()), e(block_->phisEnd()); i != e; ++i) {
         MPhi *phi = *i;
         numLPhis += (phi->type() == MIRType_Value) ? BOX_PIECES : 1;
     }
 
     // Allocate space for the LPhis.
     if (!phis_.init(alloc, numLPhis))
-        return nullptr;
+        return false;
 
     // For each MIR phi, set up LIR phis as appropriate. We'll fill in their
     // operands on each incoming edge, and set their definitions at the start of
     // their defining block.
     size_t phiIndex = 0;
     size_t numPreds = block_->numPredecessors();
     for (MPhiIterator i(block_->phisBegin()), e(block_->phisEnd()); i != e; ++i) {
         MPhi *phi = *i;
--- a/js/src/jsapi-tests/testCloneScript.cpp
+++ b/js/src/jsapi-tests/testCloneScript.cpp
@@ -3,17 +3,16 @@
  *
  * Test script cloning.
  */
 /* 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 "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(test_cloneScript)
 {
     JS::RootedObject A(cx, createGlobal());
     JS::RootedObject B(cx, createGlobal());
 
     CHECK(A);
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -2,17 +2,16 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  */
 /* 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 "jscntxt.h"
 
-#include "js/OldDebugAPI.h"
 #include "jsapi-tests/tests.h"
 
 using namespace js;
 
 BEGIN_TEST(testDebugger_newScriptHook)
 {
     // Test that top-level indirect eval fires the newScript hook.
     CHECK(JS_DefineDebuggerObject(cx, global));
--- a/js/src/jsapi-tests/testEnclosingFunction.cpp
+++ b/js/src/jsapi-tests/testEnclosingFunction.cpp
@@ -4,17 +4,16 @@
  * Test script cloning.
  */
 /* 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 "jsfriendapi.h"
 
-#include "js/OldDebugAPI.h"
 #include "jsapi-tests/tests.h"
 
 using namespace js;
 
 static JSFunction *foundFun = nullptr;
 
 static bool
 CheckEnclosing(JSContext *cx, unsigned argc, Value *vp)
--- a/js/src/jsapi-tests/testIntTypesABI.cpp
+++ b/js/src/jsapi-tests/testIntTypesABI.cpp
@@ -20,17 +20,16 @@
 #include "js/Date.h"
 #include "js/Debug.h"
 #include "js/GCAPI.h"
 #include "js/HashTable.h"
 #include "js/HeapAPI.h"
 #include "js/Id.h"
 /* LegacyIntTypes.h is deliberately exempted from this requirement */
 #include "js/MemoryMetrics.h"
-#include "js/OldDebugAPI.h"
 #include "js/ProfilingStack.h"
 #include "js/PropertyKey.h"
 #include "js/RequiredDefines.h"
 #include "js/RootingAPI.h"
 #include "js/SliceBudget.h"
 #include "js/StructuredClone.h"
 #include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
--- a/js/src/jsapi-tests/testMutedErrors.cpp
+++ b/js/src/jsapi-tests/testMutedErrors.cpp
@@ -1,14 +1,13 @@
 /* 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 "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "jsapi-tests/tests.h"
 
 static bool sErrorReportMuted = false;
 BEGIN_TEST(testMutedErrors)
 {
     CHECK(testOuter("function f() {return 1}; f;"));
     CHECK(testOuter("function outer() { return (function () {return 2}); }; outer();"));
     CHECK(testOuter("eval('(function() {return 3})');"));
--- a/js/src/jsapi-tests/testScriptInfo.cpp
+++ b/js/src/jsapi-tests/testScriptInfo.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  */
 /* 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 "js/OldDebugAPI.h"
+#include "jsapi.h"
+
 #include "jsapi-tests/tests.h"
 
 const char code[] =
     "xx = 1;       \n\
                    \n\
 try {              \n\
 	 debugger; \n\
                    \n\
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4588,16 +4588,46 @@ JS_BufferIsCompilableUnit(JSContext *cx,
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalFromScript(JSScript *script)
 {
     MOZ_ASSERT(!script->isCachedEval());
     return &script->global();
 }
 
+JS_PUBLIC_API(const char *)
+JS_GetScriptFilename(JSScript *script)
+{
+    // This is called from ThreadStackHelper which can be called from another
+    // thread or inside a signal hander, so we need to be careful in case a
+    // copmacting GC is currently moving things around.
+    return script->maybeForwardedFilename();
+}
+
+JS_PUBLIC_API(unsigned)
+JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
+{
+    return script->lineno();
+}
+
+JS_PUBLIC_API(JSScript *)
+JS_GetFunctionScript(JSContext *cx, HandleFunction fun)
+{
+    if (fun->isNative())
+        return nullptr;
+    if (fun->isInterpretedLazy()) {
+        AutoCompartment funCompartment(cx, fun);
+        JSScript *script = fun->getOrCreateScript(cx);
+        if (!script)
+            MOZ_CRASH();
+        return script;
+    }
+    return fun->nonLazyScript();
+}
+
 JS_PUBLIC_API(bool)
 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
                     const char *name, unsigned nargs, const char *const *argnames,
                     SourceBufferHolder &srcBuf, MutableHandleFunction fun)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3468,16 +3468,25 @@ extern JS_PUBLIC_API(bool)
 JS_CompileUCScript(JSContext *cx, JS::HandleObject obj,
                    const char16_t *chars, size_t length,
                    const JS::CompileOptions &options,
                    JS::MutableHandleScript script);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_GetGlobalFromScript(JSScript *script);
 
+extern JS_PUBLIC_API(const char *)
+JS_GetScriptFilename(JSScript *script);
+
+extern JS_PUBLIC_API(unsigned)
+JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script);
+
+extern JS_PUBLIC_API(JSScript *)
+JS_GetFunctionScript(JSContext *cx, JS::HandleFunction fun);
+
 /*
  * |fun| will always be set. On failure, it will be set to nullptr.
  */
 extern JS_PUBLIC_API(bool)
 JS_CompileFunction(JSContext *cx, JS::HandleObject obj, const char *name,
                    unsigned nargs, const char *const *argnames,
                    const char *bytes, size_t length,
                    const JS::CompileOptions &options,
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -36,17 +36,16 @@
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jstypes.h"
 #include "jswatchpoint.h"
 
 #include "gc/Marking.h"
 #include "jit/Ion.h"
 #include "js/CharacterEncoding.h"
-#include "js/OldDebugAPI.h"
 #include "vm/Debugger.h"
 #include "vm/HelperThreads.h"
 #include "vm/Shape.h"
 
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/Stack-inl.h"
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -39,17 +39,16 @@
 #include "asmjs/AsmJSModule.h"
 #include "builtin/Eval.h"
 #include "builtin/Object.h"
 #include "builtin/SymbolObject.h"
 #include "frontend/BytecodeCompiler.h"
 #include "gc/Marking.h"
 #include "jit/BaselineJIT.h"
 #include "js/MemoryMetrics.h"
-#include "js/OldDebugAPI.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Interpreter.h"
 #include "vm/ProxyObject.h"
 #include "vm/RegExpStaticsObject.h"
 #include "vm/Shape.h"
 #include "vm/TypedArrayCommon.h"
 
 #include "jsatominlines.h"
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -32,17 +32,16 @@
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/SharedContext.h"
 #include "gc/Marking.h"
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "jit/IonCode.h"
 #include "js/MemoryMetrics.h"
-#include "js/OldDebugAPI.h"
 #include "js/Utility.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Compression.h"
 #include "vm/Debugger.h"
 #include "vm/Opcodes.h"
 #include "vm/SelfHosting.h"
 #include "vm/Shape.h"
 #include "vm/Xdr.h"
--- a/js/src/jswatchpoint.h
+++ b/js/src/jswatchpoint.h
@@ -6,17 +6,16 @@
 
 #ifndef jswatchpoint_h
 #define jswatchpoint_h
 
 #include "jsalloc.h"
 
 #include "gc/Barrier.h"
 #include "js/HashTable.h"
-#include "js/OldDebugAPI.h"
 
 namespace js {
 
 struct WeakMapTracer;
 
 struct WatchKey {
     WatchKey() {}
     WatchKey(JSObject *obj, jsid id) : object(obj), id(id) {}
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -70,17 +70,16 @@ EXPORTS.js += [
     '../public/Date.h',
     '../public/Debug.h',
     '../public/GCAPI.h',
     '../public/HashTable.h',
     '../public/HeapAPI.h',
     '../public/Id.h',
     '../public/LegacyIntTypes.h',
     '../public/MemoryMetrics.h',
-    '../public/OldDebugAPI.h',
     '../public/Principals.h',
     '../public/ProfilingFrameIterator.h',
     '../public/ProfilingStack.h',
     '../public/PropertyKey.h',
     '../public/RequiredDefines.h',
     '../public/RootingAPI.h',
     '../public/SliceBudget.h',
     '../public/StructuredClone.h',
@@ -247,17 +246,16 @@ UNIFIED_SOURCES += [
     'vm/GlobalObject.cpp',
     'vm/HelperThreads.cpp',
     'vm/Id.cpp',
     'vm/Interpreter.cpp',
     'vm/JSONParser.cpp',
     'vm/MemoryMetrics.cpp',
     'vm/Monitor.cpp',
     'vm/NativeObject.cpp',
-    'vm/OldDebugAPI.cpp',
     'vm/PIC.cpp',
     'vm/Probes.cpp',
     'vm/PropertyKey.cpp',
     'vm/ProxyObject.cpp',
     'vm/RegExpObject.cpp',
     'vm/RegExpStatics.cpp',
     'vm/Runtime.cpp',
     'vm/SavedStacks.cpp',
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -59,17 +59,16 @@
 #include "jswrapper.h"
 #include "prmjtime.h"
 
 #include "builtin/TestingFunctions.h"
 #include "frontend/Parser.h"
 #include "jit/arm/Simulator-arm.h"
 #include "jit/Ion.h"
 #include "js/Debug.h"
-#include "js/OldDebugAPI.h"
 #include "js/StructuredClone.h"
 #include "perf/jsperf.h"
 #include "shell/jsheaptools.h"
 #include "shell/jsoptparse.h"
 #include "shell/OSObject.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Debugger.h"
 #include "vm/HelperThreads.h"
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -16,16 +16,24 @@
 #include "jsweakmap.h"
 #include "jswrapper.h"
 
 #include "gc/Barrier.h"
 #include "js/HashTable.h"
 #include "vm/GlobalObject.h"
 #include "vm/SavedStacks.h"
 
+typedef enum JSTrapStatus {
+    JSTRAP_ERROR,
+    JSTRAP_CONTINUE,
+    JSTRAP_RETURN,
+    JSTRAP_THROW,
+    JSTRAP_LIMIT
+} JSTrapStatus;
+
 namespace js {
 
 class Breakpoint;
 class DebuggerMemory;
 
 /*
  * A weakmap that supports the keys being in different compartments to the
  * values, although all values must be in the same compartment.
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -29,17 +29,16 @@
 #include "jsprf.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
 #include "builtin/Eval.h"
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "jit/IonAnalysis.h"
-#include "js/OldDebugAPI.h"
 #include "vm/Debugger.h"
 #include "vm/Opcodes.h"
 #include "vm/Shape.h"
 #include "vm/TraceLogging.h"
 
 #include "jsatominlines.h"
 #include "jsboolinlines.h"
 #include "jsfuninlines.h"
deleted file mode 100644
--- a/js/src/vm/OldDebugAPI.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * 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/. */
-
-/*
- * JS debugging API.
- */
-
-#include "js/OldDebugAPI.h"
-
-#include <string.h>
-
-#include "jscntxt.h"
-#include "jsfun.h"
-#include "jsgc.h"
-#include "jsobj.h"
-#include "jsopcode.h"
-#include "jsprf.h"
-#include "jsscript.h"
-#include "jsstr.h"
-#include "jstypes.h"
-
-#include "frontend/SourceNotes.h"
-#include "vm/Debugger.h"
-#include "vm/Shape.h"
-
-#include "jsatominlines.h"
-#include "jsinferinlines.h"
-#include "jsscriptinlines.h"
-
-#include "vm/Debugger-inl.h"
-#include "vm/Interpreter-inl.h"
-#include "vm/Stack-inl.h"
-
-using namespace js;
-using namespace js::gc;
-
-using mozilla::PodZero;
-
-JS_PUBLIC_API(JSScript *)
-JS_GetFunctionScript(JSContext *cx, HandleFunction fun)
-{
-    if (fun->isNative())
-        return nullptr;
-    if (fun->isInterpretedLazy()) {
-        AutoCompartment funCompartment(cx, fun);
-        JSScript *script = fun->getOrCreateScript(cx);
-        if (!script)
-            MOZ_CRASH();
-        return script;
-    }
-    return fun->nonLazyScript();
-}
-
-/************************************************************************/
-
-JS_PUBLIC_API(const char *)
-JS_GetScriptFilename(JSScript *script)
-{
-    // This is called from ThreadStackHelper which can be called from another
-    // thread or inside a signal hander, so we need to be careful in case a
-    // copmacting GC is currently moving things around.
-    return script->maybeForwardedFilename();
-}
-
-JS_PUBLIC_API(unsigned)
-JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
-{
-    return script->lineno();
-}
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -12,17 +12,16 @@
 #include "jsfun.h"
 #include "jsscript.h"
 
 #include "asmjs/AsmJSFrameIterator.h"
 #include "jit/JitFrameIterator.h"
 #ifdef CHECK_OSIPOINT_REGISTERS
 #include "jit/Registers.h" // for RegisterDump
 #endif
-#include "js/OldDebugAPI.h"
 
 struct JSCompartment;
 struct JSGenerator;
 
 namespace js {
 
 class ArgumentsObject;
 class AsmJSModule;
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -40,18 +40,16 @@
 
 #include "mozilla/AddonPathService.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 #include "mozilla/MacroForEach.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/ScriptSettings.h"
 
-#include "js/OldDebugAPI.h"
-
 using namespace mozilla;
 using namespace mozilla::scache;
 using namespace xpc;
 using namespace JS;
 
 // This JSClass exists to trick silly code that expects toString()ing the
 // global in a component scope to return something with "BackstagePass" in it
 // to continue working.
--- a/js/xpconnect/loader/mozJSLoaderUtils.cpp
+++ b/js/xpconnect/loader/mozJSLoaderUtils.cpp
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAutoPtr.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 
 #include "nsJSPrincipals.h"
 
 #include "mozilla/scache/StartupCache.h"
 
 using namespace JS;
 using namespace mozilla::scache;
 
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -16,17 +16,16 @@
 #include "nsNetUtil.h"
 #include "nsIFileURL.h"
 #include "nsScriptLoader.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsThreadUtils.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "nsJSPrincipals.h"
 #include "xpcprivate.h" // For xpc::OptionsBase
 #include "jswrapper.h"
 
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 #include "mozilla/unused.h"
 #include "nsContentUtils.h"
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -6,17 +6,16 @@
 
 /*
  * The Components.Sandbox object.
  */
 
 #include "AccessCheck.h"
 #include "jsfriendapi.h"
 #include "jsproxy.h"
-#include "js/OldDebugAPI.h"
 #include "js/StructuredClone.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIURI.h"
 #include "nsJSUtils.h"
--- a/js/xpconnect/src/XPCDebug.cpp
+++ b/js/xpconnect/src/XPCDebug.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
 /* 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 "xpcprivate.h"
 #include "jsprf.h"
-#include "js/OldDebugAPI.h"
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
 static void DebugDump(const char* fmt, ...)
 {
   char buffer[2048];
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -30,17 +30,16 @@
 
 #include "nsContentUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsCycleCollectionNoteRootCallback.h"
 #include "nsScriptLoader.h"
 #include "jsfriendapi.h"
 #include "jsprf.h"
 #include "js/MemoryMetrics.h"
-#include "js/OldDebugAPI.h"
 #include "mozilla/dom/GeneratedAtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/WindowBinding.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "AccessCheck.h"
 #include "nsGlobalWindow.h"
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsXULAppAPI.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jsprf.h"
-#include "js/OldDebugAPI.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIXPConnect.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsIServiceManager.h"
 #include "nsIFile.h"
 #include "nsString.h"
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -8,17 +8,16 @@
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Base64.h"
 #include "mozilla/Likely.h"
 
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "nsJSEnvironment.h"
 #include "nsThreadUtils.h"
 #include "nsDOMJSUtils.h"
 
 #include "WrapperFactory.h"
 #include "AccessCheck.h"
 
 #include "XPCQuickStubs.h"
--- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
@@ -166,17 +166,17 @@ WebrtcGmpVideoEncoder::InitEncode(const 
 int32_t
 WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
                                     int32_t aNumberOfCores,
                                     uint32_t aMaxPayloadSize)
 {
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_LITERAL_CSTRING("h264"));
   if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags,
-                                                    NS_LITERAL_STRING(""),
+                                                    NS_LITERAL_CSTRING(""),
                                                     &mHost,
                                                     &mGMP)))) {
     mMPS = nullptr;
     mGMP = nullptr;
     mGMPThread = nullptr;
     mHost = nullptr;
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
@@ -250,17 +250,17 @@ WebrtcGmpVideoEncoder::Encode_g(const we
     mGMP->Close();
 
     // OpenH264 codec (at least) can't handle dynamic input resolution changes
     // re-init the plugin when the resolution changes
     // XXX allow codec to indicate it doesn't need re-init!
     nsTArray<nsCString> tags;
     tags.AppendElement(NS_LITERAL_CSTRING("h264"));
     if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags,
-                                                      NS_LITERAL_STRING(""),
+                                                      NS_LITERAL_CSTRING(""),
                                                       &mHost,
                                                       &mGMP)))) {
       mGMP = nullptr;
       mHost = nullptr;
       return WEBRTC_VIDEO_CODEC_ERROR;
     }
 
     mCodecParams.mWidth = aInputImage->width();
@@ -553,17 +553,17 @@ WebrtcGmpVideoDecoder::InitDecode(const 
 
 int32_t
 WebrtcGmpVideoDecoder::InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
                                     int32_t aNumberOfCores)
 {
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_LITERAL_CSTRING("h264"));
   if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoder(&tags,
-                                                    NS_LITERAL_STRING(""),
+                                                    NS_LITERAL_CSTRING(""),
                                                     &mHost,
                                                     &mGMP)))) {
     mMPS = nullptr;
     mGMP = nullptr;
     mGMPThread = nullptr;
     mHost = nullptr;
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -198,25 +198,25 @@ int VcmSIPCCBinding::getVideoCodecsGmp()
   // XXX I'd prefer if this was all known ahead of time...
 
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_LITERAL_CSTRING("h264"));
 
   // H.264 only for now
   bool has_gmp;
   nsresult rv;
-  rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_STRING(""),
+  rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
                                            NS_LITERAL_CSTRING("encode-video"),
                                            &tags,
                                            &has_gmp);
   if (NS_FAILED(rv) || !has_gmp) {
     return 0;
   }
 
-  rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_STRING(""),
+  rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
                                            NS_LITERAL_CSTRING("decode-video"),
                                            &tags,
                                            &has_gmp);
   if (NS_FAILED(rv) || !has_gmp) {
     return 0;
   }
 
   return VCM_CODEC_RESOURCE_H264;
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -256,9 +256,9 @@ user_pref("loop.CSP","default-src 'self'
 
 // Ensure UITour won't hit the network
 user_pref("browser.uitour.pinnedTabUrl", "http://%(server)s/uitour-dummy/pinnedTab");
 user_pref("browser.uitour.url", "http://%(server)s/uitour-dummy/tour");
 
 user_pref("media.eme.enabled", true);
 
 // Don't prompt about e10s
-user_pref("browser.displayedE10SPrompt", 5);
+user_pref("browser.displayedE10SPrompt.1", 5);
--- a/toolkit/devtools/server/nsJSInspector.cpp
+++ b/toolkit/devtools/server/nsJSInspector.cpp
@@ -2,17 +2,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 "nsJSInspector.h"
 #include "nsIXPConnect.h"
 #include "nsThreadUtils.h"
 #include "jsfriendapi.h"
-#include "js/OldDebugAPI.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsServiceManagerUtils.h"
 #include "nsMemory.h"
 #include "nsArray.h"
 #include "nsTArray.h"
 
deleted file mode 100644
--- a/tools/footprint/README.reports
+++ /dev/null
@@ -1,113 +0,0 @@
-                 Gross Dynamic Footprint Reports
-             Chris Waterson <waterson@netscape.com>
-                      November 16, 2000
-
-This is a short primer on how to run the ``gross dynamic footprint''
-reports.
-
-Win32
------
-
-I've tried this on Win2K. Should work on NT, probably not 98.
-
-1. Configure your machine with a ``standard'' mozilla build
-environment, as described at:
-
-  http://www.mozilla.org/build/win32.html
-
-Specifically, you'll need the Cygnus tools (GNU make, awk, sed), which
-can be downloaded from:
-
-  http://sourceware.cygnus.com/cygwin/download.html
-
-2. Install the Win32 version of GNUplot, avaialable from:
-
-  ftp://ftp.dartmouth.edu/pub/gnuplot/gnuplot3.7cyg.zip
-
-3. Configure a web server with the ``buster.cgi'' CGI script contained
-in this directory.
-
-4. Pull and build a ``release'' build. Besides the normal Win32 flags
-described on the Win32 build instructions, be sure that you've set the
-following:
-
-  set BUILD_OPT=1
-  set MOZ_DEBUG=
-
-That is, MOZ_DEBUG should be unset.
-
-5. To collect data and build the dynamic footprint graph, type the
-following command from the mozilla/tools/footprint directory:
-
-  make --unix -fwin32-gdf.mk \
-    BUSTER_URL="http://myserver/cgi-bin/buster.cgi?refresh=10"
-
-(Replace ``myserver'' with the name of the webserver where you
-installed ``buster.cgi'' in step 3, above.)
-
-This should:
-
-  - Build ``wm.exe'', which will spy on memory usage.
-  - Run the winEmbed program over the top 100 URLs (from top100.txt)
-    to generate a file called ``winEmbed.dat''
-  - Run mozilla over the top 100 URLs to generate a file called
-    ``mozilla.dat''
-  - Use gnuplot to create a PNG image file called win32-gdf.png
-
-Linux
------
-
-1. Configure your machine with a ``standard'' mozilla build
-environment, as described at:
-
-  http://www.mozilla.org/build/unix.html
-
-2. Install GNUplot, which is available as an RPM on RedHat-6.2 CDs
-(probably others, as well).
-
-3. Configure a web server with the ``buster.cgi'' CGI script contained
-in this directory.
-
-4. Pull and build a ``release build''. Here are the settings you
-should use in your .mozconfig file:
-
-   ac_add_options --enable-optimize
-   ac_add_options --disable-debug
-   ac_add_options --enable-strip-libs
-
-5. To collect data and build the dynamic footprint graph, type the
-following command from the mozilla/tools/footprint directory:
-
-  make -flinux-gdf.mk \
-    BUSTER_URL="http://myserver/cgi-bin/buster.cgi?refresh=10"
-
-(Replace ``myserver'' with the name of the webserver where you
-installed ``buster.cgi'' in step 3, above.)
-
-Details, details, details
--------------------------
-
-1. When running these tests, you'll probably want to use predictable
-cache settings. You can modify $(DIST)/bin/defaults/pref/all.js to
-tweak settings that will be used by [win|gtk]Embed (these programs
-ignore profile-specific settings AFAIK). For example, I've used these
-to try to cull out cache usage altogether:
-
-  pref("browser.cache.disk_cache_size",       0);
-  pref("browser.cache.enable",                false);
-  pref("browser.cache.disk.enable",           false);
-  pref("browser.cache.memory_cache_size",     0);
-  pref("browser.cache.disk_cache_ssl",        false);
-
-I think the image cache has a pref that you can use to shut it off as
-well. Haven't found it yet.
-
-2. If you collect data using Mozilla (as Win32 will do, by default), I
-recommend using a clean profile for consistency's sake. Otherwise,
-results will vary based on random stuff like how big your bookmarks
-are, how big your global history is, whether or not you've started
-mail, etc.
-
-3. I removed the ``plugin downloader plugin'' libnullplugin.so, as
-well as all other plugins, from $(DIST)/bin/plugins so that no plugins
-would be loaded.
deleted file mode 100755
--- a/tools/footprint/buster.cgi
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/perl
-#
-# 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/.
-
-# This is a modified version of Chris Hofmann's <chofmann@netscape.com>
-# infamous "browser buster" test harness. It's a bit simpler (CGI
-# instead of using cookies; IFRAME instead of FRAMESET), and has some
-# extra parameters that make it a bit easier to test with, but it's
-# pretty faithful otherwise.
-#
-# It accepts a couple of parameters, including
-#
-#   file=<filename> Set this to the name of the file containing
-#     the URLs that you want the buster to cycle through. This
-#     might be a security hole, so don't run this script on a
-#     server with s3kret stuff on it, mmkay?
-#
-#   page=<number> This is used to maintain state, and is the line
-#     number in the file that the buster will pull up in the
-#     IFRAME. Set if by hand if you need to for some reason.
-#
-#   last=<number> The buster will run until it's exhausted all
-#     the URLs in the file, or until it reaches this line in the
-#     file; e.g., setting it to "5" will load five URLs.
-#
-#   refresh=<number> The timeout (in seconds) to wait before doing
-#     a page refresh, and thus loading the next URL. Defaults to
-#     thirty.
-
-use CGI;
-
-# Find the page'th URL in the file with the specified name
-sub FindURL($$)
-{
-    my ($file, $page) = @_;
-
-    open URLS, $file
-        || die("can't open $::File");
-
-    LINE: while (<URLS>) {
-        next LINE if /^#/;
-        last LINE unless --$page;
-    }
-
-    close URLS;
-
-    chomp;
-    return $_;
-}
-
-# Scrape parameters
-$::Query = new CGI;
-
-$::File = $::Query->param("file");
-$::File = "top100.txt" unless $::File;
-
-$::Page = $::Query->param("page");
-$::Page = 0 unless $::Page;
-$::URL = FindURL($::File, ++$::Page);
-
-$::Last = $::Query->param("last");
-$::Last = -1 unless $::Last;
-
-$::Refresh = $::Query->param("refresh");
-$::Refresh = 30 unless $::Refresh;
-
-# Header
-print qq{Content-type: text/html
-
-<html>
-<head>
-};
-
-# Meat
-if ($::URL && ($::Page <= $::Last || $::Last == -1)) {
-    # Make a web page that'll load $::URL in an IFRAME, with
-    # a meta-refresh that'll reload us again in short order.
-    print qq{<meta http-equiv="Pragma" content="no-cache">
-<meta http-equiv="refresh" content="$::Refresh;url=buster.cgi?file=$::File&page=$::Page&last=$::Last&refresh=$::Refresh">
-<title>BrowserBuster II: $::URL</title>
-<style type="text/css">
-body {
-  overflow: hidden;
-  border: 0;
-  margin: 0;
-}
-</style>
-</head>
-<script>
-dump("+++ loading $::URL\\n");
-</script>
-<body>
-};
-    print "$::File: $::URL";
-    if ($::Last != -1) {
-        print " ($::Page of $::Last)<br>";
-    }
-    print qq{
-<iframe width="100%" height="100%" src="$::URL">
-};
-}
-else {
-    # Make a web page that'll close the current browser
-    # window, terminating the test app.
-    print qq{<head>
-<title>BrowserBuster II: Done!</title>
-<body onload="window.close();">
-All done!
-};
-}
-
-# Footer
-print qq{</body>
-</html>
-};
deleted file mode 100644
--- a/tools/footprint/create_dat.awk
+++ /dev/null
@@ -1,21 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-BEGIN     { COUNT = 1
-            if (TYPE == "") TYPE = "vms";
-          }
-
-/^[0-9]/  { if      (TYPE == "vms") print COUNT, $1;
-            else if (TYPE == "vmd") print COUNT, $4;
-            else if (TYPE == "vmx") print COUNT, $2 + $3;
-            else if (TYPE == "rss") print COUNT, $6;
-
-            COUNT = COUNT + 1;
-          }
-
-/^ /      { print COUNT, "0";
-            COUNT = COUNT + 1; \
-          }
-
-
deleted file mode 100644
--- a/tools/footprint/foldelf.cpp
+++ /dev/null
@@ -1,319 +0,0 @@
-/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * 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/. */
-
-/* This program reads an ELF file and computes information about
- * redundancies. 
- */
-
-#include <algorithm>
-#include <fstream>
-#include <string>
-#include <vector>
-#include <map>
-#include <elf.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <getopt.h>
-
-//----------------------------------------------------------------------
-
-char* opt_type    = "func";
-char* opt_section = ".text";
-
-//----------------------------------------------------------------------
-
-static void
-hexdump(ostream& out, const char* bytes, size_t count)
-{
-    hex(out);
-
-    size_t off = 0;
-    while (off < count) {
-        out.form("%08lx: ", off);
-
-        const char* p = bytes + off;
-
-        int j = 0;
-        while (j < 16) {
-            out.form("%02x", p[j++] & 0xff);
-            if (j + off >= count)
-                break;
-
-            out.form("%02x ", p[j++] & 0xff);
-            if (j + off >= count)
-                break;
-        }
-
-        // Pad
-        for (; j < 16; ++j)
-            out << ((j%2) ? "   " : "  ");
-
-        for (j = 0; j < 16; ++j) {
-            if (j + off < count)
-                out.put(isprint(p[j]) ? p[j] : '.');
-        }
-
-        out << endl;
-        off += 16;
-    }
-}
-
-//----------------------------------------------------------------------
-
-int
-verify_elf_header(const Elf32_Ehdr* hdr)
-{
-    if (hdr->e_ident[EI_MAG0] != ELFMAG0
-        || hdr->e_ident[EI_MAG1] != ELFMAG1
-        || hdr->e_ident[EI_MAG2] != ELFMAG2
-        || hdr->e_ident[EI_MAG3] != ELFMAG3) {
-        cerr << "not an elf file" << endl;
-        return -1;
-    }
-
-    if (hdr->e_ident[EI_CLASS] != ELFCLASS32) {
-        cerr << "not a 32-bit elf file" << endl;
-        return -1;
-    }
-
-    if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
-        cerr << "not a little endian elf file" << endl;
-        return -1;
-    }
-
-    if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
-        cerr << "incompatible version" << endl;
-        return -1;
-    }
-
-    return 0;
-}
-
-//----------------------------------------------------------------------
-
-class elf_symbol : public Elf32_Sym
-{
-public:
-    elf_symbol(const Elf32_Sym& sym)
-    { ::memcpy(static_cast<Elf32_Sym*>(this), &sym, sizeof(Elf32_Sym)); }
-
-    friend bool operator==(const elf_symbol& lhs, const elf_symbol& rhs) {
-        return 0 == ::memcmp(static_cast<const Elf32_Sym*>(&lhs),
-                             static_cast<const Elf32_Sym*>(&rhs),
-                             sizeof(Elf32_Sym)); }
-};
-
-//----------------------------------------------------------------------
-
-static const char*
-st_bind(unsigned char info)
-{
-    switch (ELF32_ST_BIND(info)) {
-    case STB_LOCAL:      return "local";
-    case STB_GLOBAL:     return "global";
-    case STB_WEAK:       return "weak";
-    default:             return "unknown";
-    }
-}
-
-static const char*
-st_type(unsigned char info)
-{
-    switch (ELF32_ST_TYPE(info)) {
-    case STT_NOTYPE:     return "none";
-    case STT_OBJECT:     return "object";
-    case STT_FUNC:       return "func";
-    case STT_SECTION:    return "section";
-    case STT_FILE:       return "file";
-    default:             return "unknown";
-    }
-}
-
-static unsigned char
-st_type(const char* type)
-{
-    if (strcmp(type, "none") == 0) {
-        return STT_NOTYPE;
-    }
-    else if (strcmp(type, "object") == 0) {
-        return STT_OBJECT;
-    }
-    else if (strcmp(type, "func") == 0) {
-        return STT_FUNC;
-    }
-    else {
-        return 0;
-    }
-}
-
-//----------------------------------------------------------------------
-
-typedef vector<elf_symbol> elf_symbol_table;
-typedef map< basic_string<char>, elf_symbol_table > elf_text_map;
-
-void
-process_mapping(char* mapping, size_t size)
-{
-    const Elf32_Ehdr* ehdr = reinterpret_cast<Elf32_Ehdr*>(mapping);
-    if (verify_elf_header(ehdr) < 0)
-        return;
-
-    // find the section headers
-    const Elf32_Shdr* shdrs = reinterpret_cast<Elf32_Shdr*>(mapping + ehdr->e_shoff);
-
-    // find the section header string table, .shstrtab
-    const Elf32_Shdr* shstrtabsh = shdrs + ehdr->e_shstrndx;
-    const char* shstrtab = mapping + shstrtabsh->sh_offset;
-
-    // find the sections we care about
-    const Elf32_Shdr *symtabsh, *strtabsh, *textsh;
-    int textndx;
-
-    for (int i = 0; i < ehdr->e_shnum; ++i) {
-        basic_string<char> name(shstrtab + shdrs[i].sh_name);
-        if (name == opt_section) {
-            textsh = shdrs + i;
-            textndx = i;
-        }
-        else if (name == ".symtab") {
-            symtabsh = shdrs + i;
-        }
-        else if (name == ".strtab") {
-            strtabsh = shdrs + i;
-        }
-    }
-
-    // find the .strtab
-    char* strtab = mapping + strtabsh->sh_offset;
-
-    // find the .text
-    char* text = mapping + textsh->sh_offset;
-    int textaddr = textsh->sh_addr;
-
-    // find the symbol table
-    int nentries = symtabsh->sh_size / sizeof(Elf32_Sym);
-    Elf32_Sym* symtab = reinterpret_cast<Elf32_Sym*>(mapping + symtabsh->sh_offset);
-
-    // look for symbols in the .text section
-    elf_text_map textmap;
-
-    for (int i = 0; i < nentries; ++i) {
-        const Elf32_Sym* sym = symtab + i;
-        if (sym->st_shndx == textndx &&
-            ELF32_ST_TYPE(sym->st_info) == st_type(opt_type) &&
-            sym->st_size) {
-            basic_string<char> functext(text + sym->st_value - textaddr, sym->st_size);
-
-            elf_symbol_table& syms = textmap[functext];
-            if (syms.end() == find(syms.begin(), syms.end(), elf_symbol(*sym)))
-                syms.insert(syms.end(), *sym);
-        }
-    }
-
-    int uniquebytes = 0, totalbytes = 0;
-    int uniquecount = 0, totalcount = 0;
-
-    for (elf_text_map::const_iterator entry = textmap.begin();
-         entry != textmap.end();
-         ++entry) {
-        const elf_symbol_table& syms = entry->second;
-
-        if (syms.size() <= 1)
-            continue;
-
-        int sz = syms.begin()->st_size;
-        uniquebytes += sz;
-        totalbytes += sz * syms.size();
-        uniquecount += 1;
-        totalcount += syms.size();
-
-        for (elf_symbol_table::const_iterator sym = syms.begin(); sym != syms.end(); ++sym)
-            cout << strtab + sym->st_name << endl;
-
-        dec(cout);
-        cout << syms.size() << " copies of " << sz << " bytes";
-        cout << " (" << ((syms.size() - 1) * sz) << " redundant bytes)" << endl;
-
-        hexdump(cout, entry->first.data(), entry->first.size());
-        cout << endl;
-    }
-
-    dec(cout);
-    cout << "bytes unique=" << uniquebytes << ", total=" << totalbytes << endl;
-    cout << "entries unique=" << uniquecount << ", total=" << totalcount << endl;
-}
-
-void
-process_file(const char* name)
-{
-    int fd = open(name, O_RDWR);
-    if (fd >= 0) {
-        struct stat statbuf;
-        if (fstat(fd, &statbuf) >= 0) {
-            size_t size = statbuf.st_size;
-
-            void* mapping = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
-            if (mapping != MAP_FAILED) {
-                process_mapping(static_cast<char*>(mapping), size);
-                munmap(mapping, size);
-            }
-        }
-        close(fd);
-    }
-}
-
-static void
-usage()
-{
-    cerr << "foldelf [--section=<section>] [--type=<type>] [file ...]\n\
-   --section, -s  the section of the ELF file to scan; defaults\n\
-                  to ``.text''. Valid values include any section\n\
-                  of the ELF file.\n\
-   --type, -t     the type of object to examine in the section;\n\
-                  defaults to ``func''. Valid values include\n\
-                  ``none'', ``func'', or ``object''.\n";
-
-}
-
-static struct option opts[] = {
-    { "type",    required_argument, 0, 't' },
-    { "section", required_argument, 0, 's' },
-    { "help",    no_argument,       0, '?' },
-    { 0,         0, 0, 0 }
-};
-    
-int
-main(int argc, char* argv[])
-{
-    while (1) {
-        int option_index = 0;
-        int c = getopt_long(argc, argv, "t:s:", opts, &option_index);
-
-        if (c < 0) break;
-
-        switch (c) {
-        case 't':
-            opt_type = optarg;
-            break;
-
-        case 's':
-            opt_section = optarg;
-            break;
-
-        case '?':
-            usage();
-            break;
-        }
-    }
-
-    for (int i = optind; i < argc; ++i)
-        process_file(argv[i]);
-
-    return 0;
-}
deleted file mode 100644
--- a/tools/footprint/foldelf.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-foldelf: foldelf.cpp
-	$(CXX) -O -o foldelf foldelf.cpp
-
-clean:
-	rm -f *.o test *.test foldelf *~
-
deleted file mode 100755
--- a/tools/footprint/linear-regression.awk
+++ /dev/null
@@ -1,58 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-function regress(DATAPOINTS,SX,SY,SXY,SX2)
-{
-   b1 = (DATAPOINTS * SXY - SX * SY) / (DATAPOINTS * SX2 - SX * SX);
-   b0 = (SY - b1 * SX ) / DATAPOINTS;
-   return b1 " * x + " b0; 
-}
-
-BEGIN {
-        if (!Skip) Skip = 0;
-        if (Interval) 
-        {
-           Count = 0;
-           IntervalCount = 0;
-        }
-      }
-
-NR>Skip {
-        sx += $1;
-        sy += $2;
-        sxy += $1 * $2;
-        sx2 += $1 * $1;
-        #print NR " " sx " " sy " " sxy " " sx2
-
-        if (Interval)
-        {
-           if(Count == Interval-1)
-           {
-              IntervalCount += 1;
-
-              print NR-Count, "-", NR, ":  ", regress(Count,isx,isy,isxy,isx2);
-
-              Count = 0;
-              isx = 0;
-              isy = 0;
-              isxy = 0;
-              isx2 = 0;
-           }
-           else
-           {
-              Count += 1;
-              isx += $1;
-              isy += $2;
-              isxy += $1 * $2;
-              isx2 += $1 * $1;
-           }
-        }
-     }
-
-END {
-       if(Interval) {
-          print NR-Count, "-", NR, ":  ", regress(Count,isx,isy,isxy,isx2);
-       }
-       print regress(NR-Skip, sx, sy, sxy, sx2); 
-    }
deleted file mode 100644
--- a/tools/footprint/linux-gdf.mk
+++ /dev/null
@@ -1,93 +0,0 @@
-# -*- Mode: Makefile -*-
-#
-# 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/.
-
-# This makefile will run Mozilla (or the program you specify), observe
-# the program's memory status using the /proc filesystem, and generate
-# a ``gross dynamic footprint'' graph using gnuplot.
-#
-# Usage:
-#
-#   make MOZILLA_DIR=<mozilla-dir> PROGRAM=<program> URL=<url>
-#
-# e.g.,
-#
-#   make -flinux-gdf.mk \
-#     MOZILLA_DIR=/export2/waterson/seamonkey-opt/mozilla/dist/bin \
-#     PROGRAM=gtkEmbed \
-#     BUSTER_URL="http://localhost/cgi-bin/buster.cgi?refresh=10"
-#
-# To use this program, you'll need to:
-#
-# 1. Install gnuplot, e.g., using your RedHat distro.
-# 2. Install the "buster.cgi" script onto a webserver somewhere
-# 3. Have a mozilla build.
-#
-# You can tweak ``linux.gnuplot.in'' to change the graph's output.
-
-# This script computes a line using linear regression; its output is
-# of the form:
-#
-#   <b1> * x + <b0>
-#
-# Where <b1> is the slope and <b0> is the y-intercept.
-LINEAR_REGRESSION=awk -f linear-regression.awk Skip=5
-
-INTERVAL=10
-WATCH=./watch.sh
-
-MOZILLA_DIR=../../dist/bin
-PROGRAM=gtkEmbed
-BUSTER_URL=http://localhost/cgi-bin/buster.cgi?refresh=$(INTERVAL)
-OUTFILE=linux.dat
-
-#----------------------------------------------------------------------
-# Top-level target
-#
-all: gdf.png
-
-#----------------------------------------------------------------------
-# gtkEmbed
-#
-
-.INTERMEDIATE: linux.gnuplot vms.dat vmd.dat vmx.dat rss.dat
-
-# Create a PNG image using the generated ``linux.gnuplot'' script
-gdf.png: vms.dat vmd.dat vmx.dat rss.dat linux.gnuplot
-	gnuplot linux.gnuplot
-
-# Generate a ``gnuplot'' script from ``linux.gnuplot.in'', making
-# appropriate substitutions as necessary.
-linux.gnuplot: linux.gnuplot.in vms.dat
-	sed -e "s/@PROGRAM@/$(PROGRAM)/" \
-            -e "s/@VMS-LINE@/`$(LINEAR_REGRESSION) vms.dat`/" \
-	    -e "s/@GROWTH-RATE@/`$(LINEAR_REGRESSION) vms.dat | awk '{ printf \"%0.1lf\\n\", $$1; }'`/" \
-	    -e "s/@BASE-SIZE@/`$(LINEAR_REGRESSION) vms.dat | awk '{ print $$5 + 2000; }'`/" \
-		linux.gnuplot.in > linux.gnuplot
-
-# Break the raw data file into temporary files that can be processed
-# by gnuplot directly.
-vms.dat: $(OUTFILE)
-	awk -f create_dat.awk TYPE=vms $? > $@
-
-vmd.dat: $(OUTFILE)
-	awk -f create_dat.awk TYPE=vmd $? > $@
-
-vmx.dat: $(OUTFILE)
-	awk -f create_dat.awk TYPE=vmx $? > $@
-
-rss.dat: $(OUTFILE)
-	awk -f create_dat.awk TYPE=rss $? > $@
-
-# Run $(PROGRAM) to produce $(OUTFILE)
-$(OUTFILE):
-	LD_LIBRARY_PATH=$(MOZILLA_DIR) \
-	MOZILLA_FIVE_HOME=$(MOZILLA_DIR) \
-	$(WATCH) -i $(INTERVAL) -o $@ $(MOZILLA_DIR)/$(PROGRAM) "$(BUSTER_URL)"
-
-# Clean up the mess.
-clean:
-	rm -f $(OUTFILE) gdf.png *~
-
deleted file mode 100644
--- a/tools/footprint/linux.gnuplot.in
+++ /dev/null
@@ -1,15 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-set term png color
-set output 'gdf.png'
-set title '@PROGRAM@ - Gross Dynamic Footprint'
-set xlabel 'Time (sec)'
-set ylabel 'KB'
-set key bottom right
-set label '@GROWTH-RATE@KB/sec' at 5, @BASE-SIZE@
-plot 'vms.dat' title 'Total VM Size' with line 1,\
-  @VMS-LINE@ notitle with line 1,\
-  'vmd.dat' title 'Data Size' with line 3,\
-  'vmx.dat' title 'Code Size' with line 5,\
-  'rss.dat' title 'Resident Set Size' with line 7
deleted file mode 100644
--- a/tools/footprint/lists/100.list
+++ /dev/null
@@ -1,147 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# These are the "Top 100" from chofmann's list
-#   BTW, the first url is duplicated several times under the expectation
-#   that the first 5 memory readings will be ignored as startup noise.
-http://www.yahoo.com
-http://www.yahoo.com
-http://www.yahoo.com
-http://www.yahoo.com
-http://www.yahoo.com
-http://www.yahoo.com
-http://www.netscape.com
-http://www.microsoft.com
-http://www.excite.com
-http://www.mckinley.com
-http://www.city.net
-http://www.webcrawler.com
-http://www.mirabilis.com
-http://www.infoseek.com
-http://www.pathfinder.com
-http://www.warnerbros.com
-http://www.webmd.com
-http://www.altavista.digital.com
-http://www.altavista.com
-http://www.usatoday.com
-http://www.mysap.com
-http://www.starwave.com
-http://www.hotwired.com
-http://www.statmarket.com
-http://www.lycos.com
-http://espn.go.com
-http://www.cnet.com
-http://www.search.com
-http://www.news.com
-http://www.download.com
-http://www.geocities.com
-http://www.shockwave.com
-http://www.bn.com
-http://www.imdb.com
-http://uk.imdb.com
-http://www.macromedia.com
-http://www.infobeat.com
-http://www.fxweb.com
-http://www.whowhere.com
-http://www.real.com
-http://www.sportsline.com
-http://www.dejanews.com
-http://www.the-park.com
-http://www.cmpnet.com
-http://www.go2net.com
-http://www.metacrawler.com
-http://www.playsite.com
-http://www.stocksite.com
-http://www.ameritrade.com
-http://www.zone.com
-http://www.nyse.com
-http://www.economist.com
-http://www.infospace.com
-http://www.zdnet.com
-http://www.hotfiles.com
-http://www.chathouse.com
-http://www.looksmart.com
-http://www.hotjobs.com
-http://www.macaddict.com
-http://www.benews.com
-http://www.apple.com
-http://www.beseen.com
-http://www.dogpile.com
-http://www.xoom.com
-http://www.tucows.com
-http://www.freethemes.com
-http://www.winfiles.com
-http://www.vservers.com
-http://www.mtv.com
-http://www.the-xfiles.com
-http://www.autoworld.com
-http://www.monster.com
-http://www.surplusdirect.com
-http://www.tomshardware.com
-http://www.bigyellow.com
-http://www.100hot.com
-http://www.messagemates.com
-http://www.onelist.com
-http://www.bluemountain.com
-http://www.ea.com
-http://www.bullfrog.co.uk
-http://www.travelocity.com
-http://www.pbs.com
-http://www.bigcharts.com
-http://www.davesclassics.com
-http://www.goto.com
-http://www.weather.com
-http://www.gamespot.com
-http://www.bloomberg.com
-http://www.winzip.com
-http://www.filez.com
-http://www.browserwatch.com
-http://www.internet.com
-http://www.cardmaster.com
-http://www.creaf.com
-http://netaddress.usa.net
-http://www.occ.com
-http://www.as.org
-http://www.amazon.com
-http://www.drudgereport.com
-http://www.hardradio.com
-http://www.intel.com
-http://www.mp3.com
-http://www.ebay.com
-http://www.msn.com
-http://www.fifa.com
-http://www.attitude.com
-http://www.happypuppy.com
-http://www.gamesdomain.com
-http://www.onsale.com
-http://www.tm.com
-http://www.xlnc1.com
-http://www.greatsports.com
-http://www.discovery.com
-http://www.nai.com
-http://www.nasa.gov
-http://www.os2ss.com
-http://www.warzone.com
-http://www.gamestats.com
-http://www.winamp.com
-http://java.sun.com
-http://www.hp.com
-http://www.cdnow.com
-http://www.nytimes.com
-http://www.majorleaguebaseball.com
-http://www.thestreet.com
-http://www.planetquake.com
-http://www.cnbc.com
-http://www.slashdot.org
-http://www.adobe.com
-http://www.quicken.com
-http://www.developer.com
-http://www.mapquest.com
-http://www.freshmeat.net
-http://www.bxa.doc.gov/Encryption/regs.htm
-http://www.rewards2k.com
-http://www.cnnfn.com
-http://www.blockbuster.com
-http://www.richinstyle.com/
-http://www.xml.com
deleted file mode 100644
--- a/tools/footprint/lists/500.list
+++ /dev/null
@@ -1,551 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# This is a long list (over 500 urls) which we got from AOL.
-#   BTW, the first url is duplicated several times under the expectation
-#   that the first 5 memory readings will be ignored as startup noise.
-http://www.yahoo.com
-http://www.yahoo.com
-http://www.yahoo.com
-http://www.yahoo.com
-http://www.yahoo.com
-http://www.iwin.com
-http://www.infoev.com
-http://www.ITARGET.COM
-http://www.ITN.NET
-http://www.IVILLAGE.com
-http://www.1800USSEARCH.COM
-http://www.1ST-NETCARD.COM
-http://www.3COM.COM
-http://www.4ANYTHING.COM
-http://www.50MEGS.COM
-http://www.555-1212.COM
-http://www.8M.COM
-http://www.AA.COM
-http://www.ABOUT.COM
-http://www.ACCOUNTONLINE.COM
-http://www.ACCUWEATHER.COM
-http://www.ACOP.COM
-http://www.ADOBE.COM
-http://www.ALLADVANTAGE.COM
-http://www.ALLOY.COM
-http://www.ALTAVISTA.com
-http://www.AMAZON.COM
-http://www.AMERICANEXPRESS.COM
-http://www.AMERICANGREETINGS.COM
-http://www.AMERICAONLINE.com
-http://www.AMTRAK.COM
-http://www.ANCESTRY.COM
-http://www.ANGELFIRE.COM
-http://www.ANYWHO.COM
-http://www.APPLE.COM
-http://www.ARCAMAX.COM
-http://www.ARIA.COM
-http://www.ARTISTDIRECT.COM
-http://www.ASKJEEVES.COM
-http://www.ASKME.COM
-http://www.ASTRONET.COM
-http://www.ATOMZ.COM
-http://www.ATT.NET
-http://www.AUCTIONWATCH.COM
-http://www.AUDIOHIGHWAY.COM
-http://www.AUTOBYTEL.COM
-http://www.AUTOTRADER.COM
-http://www.AUTOWEB.COM
-http://www.BABYCENTER.COM
-http://www.BACKWIRE.COM
-http://www.BANKOFAMERICA.COM
-http://www.BARGAINDOG.COM
-http://www.BARNESANDNOBLE.COM
-http://www.BASSHOTELS.COM
-http://www.BBC.CO.UK
-http://www.BERKELEY.EDU
-http://www.BESEEN.COM
-http://www.BESTBUY.COM
-http://www.BESTOFTHEWEB.COM
-http://www.BFAST.COM
-http://www.BIGBROTHER.COM
-http://www.BIGBROTHER2000.COM
-http://www.BIGFAST.NET
-http://www.BIGFATBABY.COM
-http://www.BIZLAND.COM
-http://www.BIZRATE.COM
-http://www.BLUELIGHT.COM
-http://www.BLUEMOUNTAINARTS.COM
-http://www.BMGMUSICSERVICE.COM
-http://www.BOLT.COM
-http://www.BONUSCHAT.NET
-http://www.BONZI.COM
-http://www.BOSTON.COM
-http://www.BRAVENET.COM
-http://www.BRITANNICA.COM
-http://www.BROADCAST.COM
-http://www.BUTTONWARE.NET
-http://www.BUY.COM
-http://www.CALLWAVE.COM
-http://www.CAPITALONE.COM
-http://www.CARCLUB.COM
-http://www.CAREERBUILDER.COM
-http://www.CAREERPATH.COM
-http://www.CARPOINT.COM
-http://www.CARS.COM
-http://www.CBS.COM
-http://www.CCBILL.COM
-http://www.CDNOW.COM
-http://www.CHEAPTICKETS.COM
-http://www.CHEATCC.COM
-http://www.CIRCUITCITY.COM
-http://www.CITIBANK.COM
-http://www.CITYSEARCH.com
-http://www.CJB.NET
-http://www.CLASSMATES.COM
-http://www.CLICKHERETOFIND.COM
-http://www.CNBC.COM
-http://www.CNCHOST.COM
-http://www.CNET.com
-http://www.CNN.COM
-http://www.CNNFN.COM
-http://www.CNNSI.COM
-http://www.COLLEGECLUB.COM
-http://www.COLONIZE.COM
-http://www.COLUMBIAHOUSE.COM
-http://www.COME.TO
-http://www.COMETSYSTEMS.COM
-http://www.COMMISSION-JUNCTION.COM
-http://www.COMPAQ.COM
-http://www.COMPUSERVE.COM
-http://www.COMPUTINGCENTRAL.COM
-http://www.CONDENET.com
-http://www.CONTENTMAIL.COM
-http://www.CONTINENTAL.COM
-http://www.CONXION.COM
-http://www.COOLSAVINGS.COM
-http://www.CORNELL.EDU
-http://www.CROSSWINDS.NET
-http://www.CUPCAKEPARTY.COM
-http://www.CYBERGOLD.COM
-http://www.CYBERREBATE.COM
-http://www.DAI.NET
-http://www.DASH.COM
-http://www.DEALTIME.COM
-http://www.DEJA.COM
-http://www.DELL.COM
-http://www.DELPHI.COM
-http://www.DELTA-AIR.COM
-http://www.DEMON.CO.UK
-http://www.DESTINATIONWWW.COM
-http://www.DIALPAD.COM
-http://www.DIGITALCITY.COM
-http://www.DIRECTHIT.COM
-http://www.DISCOVERCARD.COM
-http://www.DISCOVERY.COM
-http://www.DMOZ.ORG
-http://www.DOGPILE.COM
-http://www.DRKOOP.COM
-http://www.DRUGSTORE.COM
-http://www.EAAEA.COM
-http://www.EAONLINE.com
-http://www.EARTHLINK.NET
-http://www.EASYWINNING.COM
-http://www.EBAY.COM
-http://www.EDIETS.COM
-http://www.EDMUNDS.COM
-http://www.EGGHEAD.COM
-http://www.EGREETINGS.COM
-http://www.EGROUPS.COM
-http://www.EHOW.COM
-http://www.EMAZING.COM
-http://www.ENCARTA.COM
-http://www.ENEWS.COM
-http://www.ENTERTAINDOM-WARNERBROSONLINE.com
-http://www.EONLINE.COM
-http://www.EPINIONS.COM
-http://www.EROLS.COM
-http://www.ESHOP.COM
-http://www.ETOUR.COM
-http://www.ETOYS.COM
-http://www.ETRADE.COM
-http://www.EVALBUM.COM
-http://www.EVADC.ORG
-http://www.EVOICE.COM
-http://www.EW.COM
-http://www.EWANTED.COM
-http://www.EXCITE.com
-http://www.EXITFUEL.COM
-http://www.EXPAGE.COM
-http://www.EXPEDIA.COM
-http://www.EZSWEEPS.COM
-http://www.FASTWEB.COM
-http://www.FEDEX.COM
-http://www.FIDELITY.COM
-http://www.FIRSTNAME.COM
-http://www.FIRSTUSA.COM
-http://www.FLASH.NET
-http://www.FLOWGO.COM
-http://www.FOCALEX.COM
-http://www.FOODTV.COM
-http://www.FOOL.COM
-http://www.FORTUNECITY.COM
-http://www.FOUND404.COM
-http://www.FOXKIDS.COM
-http://www.FOXNEWS.COM
-http://www.FREEINTERNET.COM
-http://www.FREELOTTO.COM
-http://www.FREERIDE.COM
-http://www.FREESERVE.COM
-http://www.FREESERVERS.COM
-http://www.FREESHOP.COM
-http://www.FREEYELLOW.COM
-http://www.FUNNYGREETINGS.COM
-http://www.FUNONE.COM
-http://www.FUNSTUN.COM
-http://www.GAMESVILLE.com
-http://www.GAP.COM
-http://www.GARDEN.COM
-http://www.GASPRICEWATCH.COM
-http://www.GATEWAY.COM
-http://www.GATOR.COM
-http://www.GETSMART.COM
-http://www.GO.COM
-http://www.GO2NET.COM
-http://www.GOOGLE.COM
-http://www.GOTO.COM
-http://www.GOVERNMENTGUIDE.COM
-http://www.GREENFIELDONLINE.COM
-http://www.GTESUPERPAGES.com
-http://www.HALF.COM
-http://www.HALLMARK.COM
-http://www.HARRISPOLLONLINE.COM
-http://www.HARVARD.EDU
-http://www.HEADHUNTER.NET
-http://www.HIGHSCHOOLALUMNI.COM
-http://www.HITBOX.COM
-http://www.HOLLYWOOD.COM
-http://www.HOME.COM
-http://www.HOME.NET
-http://www.HOMEADVISOR.COM
-http://www.HOMEARTS.COM
-http://www.HOMEPAGE.COM
-http://www.HOMESTEAD.COM
-http://www.HOMESTORE.COM
-http://www.HOTJOBS.COM
-http://www.HOTMAIL.COM
-http://www.HOTSOCKET.COM
-http://www.HP.COM
-http://www.HYPERMART.NET
-http://www.IBM.COM
-http://www.ICQ.COM
-http://www.ICQ.net
-http://www.IGN.COM
-http://www.IMDB.COM
-http://www.INDIVIDUAL.COM
-http://www.INFOSPACE.COM
-http://www.INSIDETHEWEB.COM
-http://www.INTEL.com
-http://www.INTELIHEALTH.COM
-http://www.INTELLICAST.COM
-http://www.INTERNETFUEL.COM
-http://www.IPRINT.COM
-http://www.IWON.COM
-http://www.JACKPOT.COM
-http://www.JCPENNEY.COM
-http://www.JOBSONLINE.COM
-http://www.JUNO.COM
-http://www.JUSTSAYWOW.COM
-http://www.KBB.COM
-http://www.KEEN.COM
-http://www.LATIMES.com
-http://www.LAUNCH.COM
-http://www.LIFEMINDERS.COM
-http://www.LITERARYGUILD.COM
-http://www.LOOKSMART.COM
-http://www.LOWESTFARE.COM
-http://www.LUCKY7.COM
-http://www.LUCKYSURF.COM
-http://www.LYCOS.COM
-http://www.M0.NET
-http://www.NETBROADCASTER.COM
-http://www.NETFLIP.COM
-http://www.NETMARKET.COM
-http://www.NETMIND.COM
-http://www.NETSCAPE.COM
-http://www.NETSETTER.COM
-http://www.NETSONIC.COM
-http://www.NETTAXI.COM
-http://www.NETWORKSOLUTIONS.COM
-http://www.NETZIP.COM
-http://www.NEXTCARD.COM
-http://www.NFL.COM
-http://www.NFO-INTERACTIVE.COM
-http://www.NICK.COM
-http://www.NORTHERNLIGHT.COM
-http://www.NOVUSNET.COM
-http://www.NWA.COM
-http://www.NYTIMES.COM
-http://www.OFFICEDEPOT.COM
-http://www.OFFICEMAX.COM
-http://www.ONHEALTH.COM
-http://www.ONLINECREDITNOW.COM
-http://www.ONMONEY.COM
-http://www.ONRESPONSE.COM
-http://www.OPINIONFORCE.COM
-http://www.OPINIONSURVEY.COM
-http://www.OURHOUSE.COM
-http://www.OVERSTOCK.COM
-http://www.OXYGEN.COM
-http://www.PAGOO.COM
-http://www.PARAMOUNT.com
-http://www.PASSPORT.COM
-http://www.PAYPAL.COM
-http://www.PBS.ORG
-http://www.PCH.COM
-http://www.PCWORLD.COM
-http://www.PEGSINC.COM
-http://www.PENNYWEB.COM
-http://www.PETS.COM
-http://www.PETSMART.COM
-http://www.PHOTOPOINT.COM
-http://www.PHOTOWORKS.COM
-http://www.PLANETOFMUSIC.COM
-http://www.PLANETRX.COM
-http://www.POGO.COM
-http://www.PRESARIO.NET
-http://www.PREVENTION.COM
-http://www.PRICELINE.COM
-http://www.PRIZECENTRAL.COM
-http://www.PRIZES.COM
-http://www.PRODIGY.NET
-http://www.PRODUCTOPIA.COM
-http://www.PROMOGAMES.COM
-http://www.PROMOTIONS.COM
-http://www.QUICKEN.COM
-http://www.QVC.COM
-http://www.READERSDIGEST.COM
-http://www.REAL.COM
-http://www.REALNETWORKS.COM
-http://www.REALTOR.COM
-http://www.REGISTER.COM
-http://www.REGISTER-ONCE.COM
-http://www.ROCKETLINKS.COM
-http://www.ROLLINGSTONE.COM
-http://www.ROOTSWEB.COM
-http://www.RR.COM
-http://www.RSVP0.NET
-http://www.SACCITYWEB.COM
-http://www.SALESMOUNTAIN.COM
-http://www.SALON.COM
-http://www.SANDBOX.COM
-http://www.SEND4FUN.COM
-http://www.SENDAFRIEND.COM
-http://www.SENDLAUGHTER.COM
-http://www.SENDMOREINFO.COM
-http://www.SHOCKWAVE.COM
-http://www.SHOPNOW.COM
-http://www.SHOPPINGLIST.COM
-http://www.SIERRA.COM
-http://www.SIMPLENET.COM
-http://www.SLATE.COM
-http://www.SMARTBOTPRO.NET
-http://www.SMARTPAGES.COM
-http://www.SNAP.COM
-http://www.SONICNET.COM
-http://www.SONYONLINE.com
-http://www.SOUTHWEST.COM
-http://www.SPEEDYCLICK.COM
-http://www.SPINNER.COM
-http://www.SPORTINGNEWS.COM
-http://www.SPORTSLINE.COM
-http://www.SPREE.COM
-http://www.SPRINT.COM
-http://www.SPRINTPCS.COM
-http://www.STAMPS.COM
-http://www.STAPLES.COM
-http://www.STARTSAMPLING.COM
-http://www.STORERUNNER.COM
-http://www.SWEEPSCLUB.COM
-http://www.SWITCHBOARD.COM
-http://www.SWITCHOUSE.COM
-http://www.SYMANTEC.COM
-http://www.TALKCITY.COM
-http://www.TARGET.COM
-http://www.TARGETNET.COM
-http://www.THEBIRTHDAYGAME.COM
-http://www.THEGLOBE.COM
-http://www.THESTREET.COM
-http://www.THIRDAGE.COM
-http://www.THRIVEONLINE.COM
-http://www.TICKETMASTER.com
-http://www.TIME.COM
-http://www.TM0.COM
-http://www.TOYSRUS.COM
-http://www.TRAFFICINC.COM
-http://www.TRAVELNOW.COM
-http://www.TRAVELOCITY.COM
-http://www.TREELOOT.COM
-http://www.TRIP.COM
-http://www.TRIPOD.COM
-http://www.TROPPOLOTTO.COM
-http://www.TUCOWS.COM
-http://www.TVGUIDE.COM
-http://www.TWISTEDHUMOR.COM
-http://www.UBID.COM
-http://www.UIUC.EDU
-http://www.UMICH.EDU
-http://www.UNC.EDU
-http://www.UNICAST.COM
-http://www.UNITED.COM
-http://www.UPROAR.COM
-http://www.UPS.COM
-http://www.USAIRWAYS.COM
-http://www.USATODAY.COM
-http://www.USPS.COM
-http://www.UTEXAS.EDU
-http://www.VALUPAGE.COM
-http://www.VICINITY.COM
-http://www.VICTORIASSECRET.COM
-http://www.VIRTUALAVE.NET
-http://www.VIRTUALVEGAS.COM
-http://www.VSTORE.COM
-http://www.WALMART.COM
-http://www.WASHINGTONPOST.COM
-http://www.WEATHER.COM
-http://www.WEB1000.COM
-http://www.WEBCRAWLER.COM
-http://www.WEBJUMP.COM
-http://www.WEBMD.COM
-http://www.WEBRING.ORG
-http://www.WEBSHOTS.COM
-http://www.WEBSTAKES.COM
-http://www.WSJ.COM
-http://www.WUNDERGROUND.COM
-http://www.X.COM
-http://www.XDRIVE.COM
-http://www.XOOM.COM
-http://www.YAHOO.COM
-http://www.YIMG.COM
-http://www.YOUWINIT.COM
-http://www.YOUWINMAIL.COM
-http://www.ZDNET.com
-http://www.ZING.COM
-http://www.ZIP2.COM
-http://www.ZMEDIA.COM
-http://www.ZONE.COM
-http://www.1STUP.COM
-http://www.1STUP.COM
-http://www.newslink.org
-http://www.answers.com
-http://www.TheAtlantic.com
-http://www.audionet.com
-http://www.bigbook.com
-http://www.biography.com
-http://www.cartalk.com
-http://www.careermosaic.com
-http://www.thecase.com
-http://www.city.net
-http://www.coolcentral.com
-http://www.cyberatlas.com
-http://www.davecentral.com
-http://www.menusonline.com
-http://www.usnews.com
-http://www.minds.com
-http://www.epicurious.com
-http://espnet.sportszone.com
-http://live.excite.com
-http://www.freeways.com
-http://www.gamelan.com
-http://www.gw2k.com
-http://www.haring.com
-http://www.homefair.com
-http://www.hotwired.com
-http://www.industry.net
-http://www.inquiry.com
-http://rampages.onramp.net
-http://www.manslife.com
-http://www.match.com
-http://www.sjmercury.com
-http://www.777film.com
-http://www.mrshowbiz.com
-http://www.pathfinder.com
-http://www.quote.com
-http://www.rocktropolis.com
-http://www.salonmagazine.com
-http://www.sciam.com
-http://voyeur.mckinley.com
-http://wheel.ucdavis.edu
-http://www.atr.org
-http://www.stroud.com
-http://www.sun.com
-http://www.supporthelp.com
-http://www.swoon.com
-http://www.tuneup.com
-http://www.w3.org
-http://www.conductor.com
-http://www.webreference.com
-http://www.windows95.com
-http://www.bezerk.com
-http://www.zauction.com
-http://www.abc.com
-http://www.usair.com
-http://www.dec.com
-http://www.eds.com
-http://www.wang.com
-http://www.shop.com
-http://www.www.com
-http://www.nbc.com
-http://www.russia.com
-http://www.delta.com
-http://www.123.com
-http://www.horses.com
-http://www.dogs.com
-http://www.frogs.com
-http://www.france.com
-http://www.karate.com
-http://www.latin.com
-http://www.sec.com
-http://cbs.sportsline.com
-http://events.ticketmaster.com
-http://home.sprynet.com
-http://lust.ops.outpost.com
-http://members.aol.com
-http://members.visi.net
-http://members.xoom.com
-http://www.aircoinc.com
-http://www.fshr.com
-http://www.geocities.com
-http://www.mcneel.com
-http://www.microwings.com
-http://www.mirabilis.com
-http://www.netwalk.com
-http://www.nyssba.org
-http://www.syquest.com
-http://www.ussb.com
-http://www.vision3d.com
-http://www.wbwebcards.com
-http://www.webmole.com
-http://www.bluemountain.com
-http://www.cdarchive.com
-http://www.clubextreme.net
-http://www.excite.co.uk
-http://www.feehery-grind.com
-http://www.freetel.com
-http://www.lib.utexas.edu
-http://www.puzzletts.com
-http://www.speakeasy.org
-http://www.nbn.com
-http://www.pepsi.com
-http://www.acm.uiuc.edu
-http://wwww.washingtonpost.com
-http://webcrawler.com
-http://www.expedia.msn.com
-http://www.digital.com
-http://www.sportszone.com
-http://www.mdc.com
-http://www.disney.com
-http://www.riddler.com
-http://www.shareware.com
-http://www.olympic.org
-http://www.gamespot.com
-http://www.gte.com
-http://netfind.aol.com
-http://ad.doubleclick.net
deleted file mode 100644
--- a/tools/footprint/lists/static41.list
+++ /dev/null
@@ -1,61 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# List of 41 urls which are static and inside the firewall.
-# Sorted in order from biggest memory user to least memory
-#   user.
-# 1/22/01 - Added 5 international urls, so this now has 46 urls
-#   in the list (even though the name doesn't sound like it).
-http://jrgm.mcom.com/perf/loadtime5/base/www.yahoo.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.yahoo.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.yahoo.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.yahoo.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.yahoo.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.iplanet.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.voodooextreme.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.cnn.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.tomshardware.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.zdnet.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.nytimes.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.w3.org_DOML2Core
-http://jrgm.mcom.com/perf/loadtime5/base/www.nytimes.com_Table
-http://jrgm.mcom.com/perf/loadtime5/base/web.icq.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.zdnet.com_Gamespot.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.spinner.com
-http://jrgm.mcom.com/perf/loadtime5/base/espn.go.com
-http://jrgm.mcom.com/perf/loadtime5/base/home.netscape.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.travelocity.com
-http://jrgm.mcom.com/perf/loadtime5/base/news.cnet.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.time.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.wired.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.msnbc.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.excite.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.compuserve.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.digitalcity.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.aol.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.amazon.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.moviefone.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.msn.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.apple.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.quicken.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.expedia.com
-http://jrgm.mcom.com/perf/loadtime5/base/hotwired.lycos.com
-http://jrgm.mcom.com/perf/loadtime5/base/my.netscape.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.sun.com
-http://jrgm.mcom.com/perf/loadtime5/base/bugzilla.mozilla.org
-http://jrgm.mcom.com/perf/loadtime5/base/slashdot.org
-http://jrgm.mcom.com/perf/loadtime5/base/www.microsoft.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.mapquest.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.ebay.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.altavista.com
-http://jrgm.mcom.com/perf/loadtime5/base/www.google.com
-http://jrgm.mcom.com/perf/loadtime5/base/lxr.mozilla.org
-http://jrgm.mcom.com/perf/loadtime5/base/www.yahoo.com
-http://jrgm.mcom.com/perf/loadtime5/base/vanilla-page
-# International Urls:
-http://jrgm.mcom.com/perf/loadtime5/base/www.jp.aol.com/index.html
-http://jrgm.mcom.com/perf/loadtime5/base/www.zdnet.co.jp_eweek/index.html
-http://jrgm.mcom.com/perf/loadtime5/base/www.ttimes.com.tw/index.html
-http://jrgm.mcom.com/perf/loadtime5/base/www.chinacue.cn.net/index.html
-http://jrgm.mcom.com/perf/loadtime5/base/www.lesechos.fr/index.html
deleted file mode 100644
--- a/tools/footprint/thrashview.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * ``thrashview'' is a program that reads a binary stream of addresses
- * from stdin and displays the pattern graphically in a window.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <X11/Xlib.h>
-#include <fstream>
-#include <getopt.h>
-
-#define GET_DISPLAY_FD(display_) ConnectionNumber(display_)
-
-static bool opt_working_set = false;
-static bool opt_fixed = false;
-
-static Display *display;
-static Window window;
-static GC gc;
-static XColor colors[256];
-const unsigned int cellsize = 4;
-static unsigned int width = 64 * cellsize;
-static unsigned int height = 64 * cellsize;
-
-#define PAGESIZE 4096
-#define MAXPAGES 4096  // should hold 16MB worth of code
-static unsigned int minpage = static_cast<unsigned int>(-1);
-static unsigned int maxpage = 0;
-static unsigned char pages[MAXPAGES];
-
-
-/**
- * Create a simple window and the X objects we'll need to talk with it.
- */
-static int
-init()
-{
-    display = XOpenDisplay(0);
-    if (! display)
-        return 0;
-
-    window =
-        XCreateSimpleWindow(display,
-                            RootWindow(display, 0),
-                            1, 1, width, height,
-                            0,
-                            BlackPixel(display, 0),
-                            BlackPixel(display, 0));
-
-    if (! window)
-        return 0;
-
-    gc = XCreateGC(display, window, 0, 0);
-    if (! gc)
-        return 0;
-
-    // Set up a grayscale
-    const unsigned int ncolors = sizeof colors / sizeof colors[0];
-    const unsigned short step = 65536 / ncolors;
-    unsigned short brightness = 0;
-
-    XColor *color = colors;
-    XColor *limit = colors + ncolors;
-    for (; color < limit; ++color, brightness += step) {
-        color->red   = brightness;
-        color->green = brightness;
-        color->blue  = brightness;
-        XAllocColor(display, DefaultColormap(display, 0), color);
-    }
-
-    // We want exposes and resizes.
-    XSelectInput(display, window, ExposureMask | StructureNotifyMask);
-
-    XMapWindow(display, window);
-    XFlush(display);
-
-    return 1;
-}
-
-/**
- * Age pages that haven't been recently touched.
- */
-static void
-decay()
-{
-    int ws_immediate = 0, ws_longterm = 0;
-
-    unsigned char *page = pages;
-    unsigned char *limit = pages + (maxpage - minpage) + 1;
-    for (; page < limit; ++page) {
-        if (opt_working_set) {
-            if (*page == 255)
-                ++ws_immediate;
-            if (*page)
-                ++ws_longterm;
-        }
-
-        if (*page) {
-            *page /= 8;
-            *page *= 7;
-        }
-    }
-
-    if (opt_working_set) {
-        dec(cout);
-        cout << "immediate: " << ws_immediate << " pages, ";
-        cout << "longterm: " << ws_longterm << " pages, ";
-        cout << "mapped: " << ((maxpage - minpage) + 1) << " pages";
-        cout << endl;
-    }
-}
-
-/**
- * Blast the state of our pages to the screen.
- */
-static int
-handle_expose(const XExposeEvent& event)
-{
-    //printf("handle_expose(%d, %d, %d, %d)\n", event.x, event.y, event.width, event.height);
-
-    int i = event.x / cellsize;
-    int imost = i + event.width / cellsize + 1;
-
-    int j = event.y / cellsize;
-    int jmost = j + event.height / cellsize + 1;
-
-    unsigned char *last_cell = pages + maxpage - minpage;
-    unsigned char *row = pages + j;
-    for (int y = j * cellsize, ymost = jmost * cellsize;
-         y < ymost;
-         y += cellsize, row += width / cellsize) {
-        unsigned char *cell = row + i;
-        for (int x = i * cellsize, xmost = imost * cellsize;
-             x < xmost;
-             x += cellsize, ++cell) {
-            unsigned int pixel = (cell <= last_cell) ? colors[*cell].pixel : colors[0].pixel;
-            XSetForeground(display, gc, pixel);
-            XFillRectangle(display, window, gc, x, y, cellsize - 1, cellsize - 1);
-        }
-    }
-
-    XFlush(display);
-
-    return 1;
-}
-
-/**
- * Invalidate the entire window.
- */
-static void
-invalidate_window()
-{
-    XExposeEvent event;
-    event.x = event.y = 0;
-    event.width = width;
-    event.height = height;
-
-    handle_expose(event);
-}
-
-/**
- * Handle a configure event.
- */
-static int
-handle_configure(const XConfigureEvent& event)
-{
-    //printf("handle_resize(%d, %d)\n", event.width, event.height);
-    width = event.width - event.width % cellsize;
-    height = event.height;
-    return 1;
-}
-
-/**
- * Filter to select any message.
- */
-static Bool
-any_event(Display *display, XEvent *event, XPointer arg)
-{
-    return 1;
-}
-
-/**
- * An X event occurred. Process it and flush the queue.
- */
-static int
-handle_xevents()
-{
-    int ok;
-    
-    XEvent event;
-    XNextEvent(display, &event);
-    do {
-        switch (event.type) {
-        case Expose:
-            ok = handle_expose(reinterpret_cast<const XExposeEvent&>(event));
-            break;
-
-        case ConfigureNotify:
-            ok = handle_configure(reinterpret_cast<const XConfigureEvent&>(event));
-            break;
-
-        default:
-            ok = 1;
-        }
-    } while (ok && XCheckIfEvent(display, &event, any_event, 0));
-
-    return ok;
-}
-
-/**
- * Read address data from stdin.
- */
-static int
-read_addrs()
-{
-    unsigned int buf[1024];
-    ssize_t count;
-    while ((count = read(0, buf, sizeof buf)) > 0) {
-        if (count % sizeof(unsigned int))
-            cerr << "truncating unaligned read" << endl;
-
-        count /= sizeof buf[0];
-
-        unsigned int *addr = reinterpret_cast<unsigned int *>(buf);
-        unsigned int *limit = addr + count;
-
-        for (; addr < limit; ++addr) {
-            // map the address to a page
-            unsigned int page = *addr / PAGESIZE;
-
-            // XXX Don't let stray addresses bring us down. Should
-            // really fix this by knowing what the ranges of addresses
-            // we ought to expect are (e.g., by reading the symtab)
-            if (maxpage && page > maxpage && page - maxpage > MAXPAGES)
-                continue;
-
-            if (! opt_fixed) {
-                // Potentially adjust minpage and maxpage to
-                // accomodate an out-of-bounds address.
-                if (page < minpage) {
-                    if (maxpage) {
-                        // everything needs to shift.
-                        unsigned int shift = minpage - page;
-                        memmove(pages + shift, pages, maxpage - minpage);
-                        memset(pages, 0, shift);
-                    }
-                    minpage = page;
-                }
-
-                if (page > maxpage)
-                    maxpage = page;
-            }
-
-            page -= minpage;
-            pages[page] = 255;
-        }
-    }
-
-    if (count < 0 && errno != EWOULDBLOCK) {
-        perror("read");
-        return 0;
-    }
-
-    return 1;
-}
-
-/**
- * Run the program
- */
-static void
-run()
-{
-    // We want non-blocking I/O on stdin so we can select on it.
-    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
-
-    // The last time we refreshed the window.
-    struct timeval last;
-    gettimeofday(&last, 0);
-
-    int ok;
-
-    do {
-        // Select on stdin and the connection to the X server.
-        fd_set fds;
-        FD_ZERO(&fds);
-        FD_SET(STDIN_FILENO, &fds);
-        FD_SET(GET_DISPLAY_FD(display), &fds);
-
-        struct timeval tv;
-        tv.tv_sec  = 1;
-        tv.tv_usec = 0;
-
-        ok = select(GET_DISPLAY_FD(display) + 1, &fds, 0, 0, &tv);
-        if (ok < 0)
-            break;
-
-        if (maxpage) {
-            // See if we've waited long enough to refresh the window.
-            struct timeval now;
-            gettimeofday(&now, 0);
-
-            if (now.tv_sec != last.tv_sec) {
-                // At least a second has gone by. Decay and refresh.
-                last = now;
-                decay();
-                invalidate_window();
-            }
-            else if (now.tv_usec - last.tv_usec > 100000) {
-                // At least 100msec have gone by. Refresh.
-                last.tv_usec = now.tv_usec;
-                invalidate_window();
-            }
-        }
-
-        // Now check for X events and input.
-        ok = 1;
-
-        if (FD_ISSET(GET_DISPLAY_FD(display), &fds))
-            ok = handle_xevents();
-
-        if (FD_ISSET(STDIN_FILENO, &fds))
-            ok = read_addrs();
-    } while (ok);
-}
-
-/**
- * Tear down our window and stuff.
- */
-static void
-finish()
-{
-    if (window) {
-        XUnmapWindow(display, window);
-        XDestroyWindow(display, window);
-    }
-
-    if (display)
-        XCloseDisplay(display);
-}
-
-static struct option opts[] = {
-    { "working-set", no_argument,       0, 'w' },
-    { "min",         required_argument, 0, 'm' },
-    { "size",        required_argument, 0, 's' },
-    { "max",         required_argument, 0, 'x' },
-    { 0,             0,                 0, 0   }
-};
-
-static void
-usage()
-{
-    cerr << "thrashview [--working-set] [--min=<min>] [--max=<max>] [--size=<size>]" << endl;
-}
-
-/**
- * Program starts here.
- */
-int
-main(int argc, char *argv[])
-{
-    int size = 0;
-
-    while (1) {
-        int option_index = 0;
-        int c = getopt_long(argc, argv, "wm:x:s:", opts, &option_index);
-
-        if (c < 0)
-            break;
-
-        switch (c) {
-        case 'w':
-            opt_working_set = true;
-            break;
-
-        case 'm':
-            minpage = strtol(optarg, 0, 0) / PAGESIZE;
-            opt_fixed = true;
-            break;
-
-        case 's':
-            size = strtol(optarg, 0, 0) / PAGESIZE;
-            break;
-
-        case 'x':
-            maxpage = strtol(optarg, 0, 0) / PAGESIZE;
-            opt_fixed = true;
-            break;
-
-        default:
-            usage();
-            return 1;
-        }
-    }
-
-    if (minpage && !maxpage) {
-        if (!size) {
-            cerr << argv[0] << ": minpage specified without maxpage or size" << endl;
-            return 1;
-        }
-
-        maxpage = minpage + size;
-    }
-
-    if (opt_fixed && minpage > maxpage) {
-        cerr << argv[0] << ": invalid page range" << endl;
-        return 1;
-    }
-
-    if (init())
-        run();
-
-    finish();
-
-    return 0;
-}
deleted file mode 100644
--- a/tools/footprint/thrashview.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-CXXFLAGS=-O2
-LDLIBS=-L/usr/X11R6/lib -lX11
-thrashview: thrashview.cpp
deleted file mode 100644
--- a/tools/footprint/top100.txt
+++ /dev/null
@@ -1,136 +0,0 @@
-# These are the "Top 100" from chofmann's list
-http://www.yahoo.com
-http://www.netscape.com
-http://www.microsoft.com
-http://www.excite.com
-http://www.mckinley.com
-http://www.city.net
-http://www.webcrawler.com
-http://www.mirabilis.com
-http://www.infoseek.com
-http://www.pathfinder.com
-http://www.warnerbros.com
-http://www.webmd.com
-http://www.altavista.digital.com
-http://www.altavista.com
-http://www.usatoday.com
-http://www.mysap.com
-http://www.starwave.com
-http://www.hotwired.com
-http://www.statmarket.com
-http://www.lycos.com
-http://espn.go.com
-http://www.cnet.com
-http://www.search.com
-http://www.news.com
-http://www.download.com
-http://www.geocities.com
-http://www.shockwave.com
-http://www.bn.com
-http://www.imdb.com
-http://uk.imdb.com
-http://www.macromedia.com
-http://www.infobeat.com
-http://www.fxweb.com
-http://www.whowhere.com
-http://www.real.com
-http://www.sportsline.com
-http://www.dejanews.com
-http://www.the-park.com
-http://www.cmpnet.com
-http://www.go2net.com
-http://www.metacrawler.com
-http://www.playsite.com
-http://www.stocksite.com
-http://www.ameritrade.com
-http://www.zone.com
-http://www.nyse.com
-http://www.economist.com
-http://www.infospace.com
-http://www.zdnet.com
-http://www.hotfiles.com
-http://www.chathouse.com
-http://www.looksmart.com
-http://www.hotjobs.com
-http://www.macaddict.com
-http://www.benews.com
-http://www.apple.com
-http://www.beseen.com
-http://www.dogpile.com
-http://www.xoom.com
-http://www.tucows.com
-http://www.freethemes.com
-http://www.winfiles.com
-http://www.vservers.com
-http://www.mtv.com
-http://www.the-xfiles.com
-http://www.autoworld.com
-http://www.monster.com
-http://www.surplusdirect.com
-http://www.tomshardware.com
-http://www.bigyellow.com
-http://www.100hot.com
-http://www.messagemates.com
-http://www.onelist.com
-http://www.bluemountain.com
-http://www.ea.com
-http://www.bullfrog.co.uk
-http://www.travelocity.com
-http://www.pbs.com
-http://www.bigcharts.com
-http://www.davesclassics.com
-http://www.goto.com
-http://www.weather.com
-http://www.gamespot.com
-http://www.bloomberg.com
-http://www.winzip.com
-http://www.filez.com
-http://www.browserwatch.com
-http://www.internet.com
-http://www.cardmaster.com
-http://www.creaf.com
-http://netaddress.usa.net
-http://www.occ.com
-http://www.as.org
-http://www.amazon.com
-http://www.drudgereport.com
-http://www.hardradio.com
-http://www.intel.com
-http://www.mp3.com
-http://www.ebay.com
-http://www.msn.com
-http://www.fifa.com
-http://www.attitude.com
-http://www.happypuppy.com
-http://www.gamesdomain.com
-http://www.onsale.com
-http://www.tm.com
-http://www.xlnc1.com
-http://www.greatsports.com
-http://www.discovery.com
-http://www.nai.com
-http://www.nasa.gov
-http://www.os2ss.com
-http://www.warzone.com
-http://www.gamestats.com
-http://www.winamp.com
-http://java.sun.com
-http://www.hp.com
-http://www.cdnow.com
-http://www.nytimes.com
-http://www.majorleaguebaseball.com
-http://www.thestreet.com
-http://www.planetquake.com
-http://www.cnbc.com
-http://www.slashdot.org
-http://www.adobe.com
-http://www.quicken.com
-http://www.developer.com
-http://www.mapquest.com
-http://www.freshmeat.net
-http://www.bxa.doc.gov/Encryption/regs.htm
-http://www.rewards2k.com
-http://www.cnnfn.com
-http://www.blockbuster.com
-http://www.richinstyle.com/
-http://www.xml.com
deleted file mode 100755
--- a/tools/footprint/watch.sh
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-#
-# 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/.
-
-# Treats the arguments as a command that is to be forked and observed;
-# e.g.,
-#
-#   watch.sh ./mozilla -f bloaturls.txt
-#
-# Periodically snap-shots the virtual memory info of the process, and
-# dumps the output to ``watch.out''
-
-# Clear the output file
-OUTPUT_FILE=watch.out
-INTERVAL=10
-
-while [ $# -gt 0 ]; do
-    case "$1" in
-    -o) OUTPUT_FILE=$2
-        shift 2
-        ;;
-    -i) INTERVAL=$2
-        shift 2
-        ;;
-    *)  break
-        ;;
-    esac
-done
-
-rm -f ${OUTPUT_FILE}
-
-echo "vmsize vmexe vmlib vmdata vmstk vmrss" > ${OUTPUT_FILE}
-
-# treat the arguments as the command to execute
-$* &
-
-# remember the process ID
-PID=$!
-
-while [ -e /proc/${PID} ]; do
-    cat /proc/${PID}/status |\
-    awk '$1=="VmSize:" { vmsize = $2; }
-$1=="VmData:" { vmdata = $2; }
-$1=="VmStk:" { vmstk = $2; }
-$1=="VmExe:" { vmexe = $2; }
-$1=="VmLib:" { vmlib = $2; }
-$1=="VmRSS:" { vmrss = $2; }
-END { print vmsize, vmexe, vmlib, vmdata, vmstk, vmrss; }' >> ${OUTPUT_FILE}
-    sleep ${INTERVAL}
-done
deleted file mode 100644
--- a/tools/footprint/win32-gdf.mk
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- Mode: Makefile -*-
-#
-# 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/.
-
-# This makefile takes raw data files named ``winEmbed.dat'' and
-# ``mozilla.dat'' produces a graph that shows memory usage and peak
-# memory usage versus number of URLs loaded.
-#
-# The data files are assumed to be of the form:
-#
-#   <working-set-size-1> <peak-working-set-size-1>
-#   <working-set-size-2> <peak-working-set-size-2>
-#   ...
-#
-# It is also assumed that each measurement corresponds (roughly) to a
-# URL load.
-#
-# You can tweak ``win32.gnuplot.in'' to change the graph's output.
-#
-# You should use this with ``make --unix'' (which will use
-# sh.exe instead of cmd.exe to process commands); e.g.,
-#
-#   make --unix -f win32-gdf.mk \
-#     BUSTER_URL="http://localhost/cgi-bin/buster.cgi?refresh=10"
-#
-# What You'll Need
-# ----------------
-#
-# . Get gnuplot for Win32 from
-#
-#     ftp://ftp.dartmouth.edu/pub/gnuplot/gnuplot3.7cyg.zip
-#
-# . The "standard" cygwin tools that you probably already have. (If
-#   you don't have 'em, see the Win32 build instructions on
-#   mozilla.org.)
-#
-
-# This script computes a line using linear regression; its output is
-# of the form:
-#
-#   <b1> * x + <b0>
-#
-# Where <b1> is the slope and <b0> is the y-intercept.
-LINEAR_REGRESSION=awk -f linear-regression.awk
-
-PROGRAM_PATH=..\\..\\dist\\win32_o.obj\\bin
-WINEMBED_PROGRAM=winEmbed
-MOZILLA_PROGRAM=mozilla
-
-GNUPLOT=wgnuplot.exe
-BUSTER_URL=http://btek/cgi-bin/buster.cgi?refresh=10
-
-#----------------------------------------------------------------------
-# Top-level target
-#
-all: win32-gdf.png
-
-#----------------------------------------------------------------------
-# winEmbed
-#
-
-.INTERMEDIATE: winEmbed-ws.dat winEmbed-pws.dat mozilla-ws.dat mozilla-pws.dat win32.gnuplot
-
-# Create a PNG image using the generated ``win32.gnuplot'' script
-win32-gdf.png: winEmbed-ws.dat winEmbed-pws.dat mozilla-ws.dat mozilla-pws.dat win32.gnuplot
-	$(GNUPLOT) win32.gnuplot
-
-# Generate a ``gnuplot'' script from ``win32.gnuplot.in'', making
-# appropriate substitutions as necessary.
-win32.gnuplot: win32.gnuplot.in winEmbed-ws.dat mozilla-ws.dat
-	sed -e "s/@WINEMBED-WS-LINE@/`$(LINEAR_REGRESSION) winEmbed-ws.dat`/" \
-	    -e "s/@WINEMBED-GROWTH-RATE@/`$(LINEAR_REGRESSION) winEmbed-ws.dat | awk '{ printf \"%0.1f\n\", $$1; }'`/" \
-	    -e "s/@WINEMBED-BASE-SIZE@/`$(LINEAR_REGRESSION) winEmbed-ws.dat | awk '{ print $$5; }'`/" \
-	    -e "s/@MOZILLA-WS-LINE@/`$(LINEAR_REGRESSION) mozilla-ws.dat`/" \
-	    -e "s/@MOZILLA-GROWTH-RATE@/`$(LINEAR_REGRESSION) mozilla-ws.dat | awk '{ printf \"%0.1f\n\", $$1; }'`/" \
-	    -e "s/@MOZILLA-BASE-SIZE@/`$(LINEAR_REGRESSION) mozilla-ws.dat | awk '{ print $$5; }'`/" \
-		win32.gnuplot.in > $@
-
-# Break the raw data file into temporary files that can be processed
-# by gnuplot directly.
-winEmbed-ws.dat: winEmbed.dat
-	awk '{ print NR, $$1 / 1024; }' $? > $@
-
-winEmbed-pws.dat: winEmbed.dat
-	awk '{ print NR, $$2 / 1024; }' $? > $@
-
-mozilla-ws.dat: mozilla.dat
-	awk '{ print NR, $$1 / 1024; }' $? > $@
-
-mozilla-pws.dat: mozilla.dat	
-	awk '{ print NR, $$2 / 1024; }' $? > $@
-
-# Run programs to collect data
-winEmbed.dat: wm.exe
-	cmd /c "start $(PROGRAM_PATH)\\$(WINEMBED_PROGRAM) $(BUSTER_URL) && .\\wm $(WINEMBED_PROGRAM) > $@"
-
-mozilla.dat: wm.exe
-	cmd /c "start $(PROGRAM_PATH)\\$(MOZILLA_PROGRAM) $(BUSTER_URL) && .\\wm $(MOZILLA_PROGRAM) > $@"
-
-# Build ``wm.exe'', the memory spy
-wm.exe: wm.cpp
-	cl -Od -Zi wm.cpp advapi32.lib
-
-# Clean up the mess.
-clean:
-	rm -f wm.exe *-gdf.png *.dat *~
-
deleted file mode 100644
--- a/tools/footprint/win32.gnuplot.in
+++ /dev/null
@@ -1,17 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-set term png color
-set output 'win32-gdf.png'
-set title 'Win32 - Gross Dynamic Footprint'
-set xlabel 'URLs'
-set ylabel 'KB'
-set key top left
-set label '@WINEMBED-GROWTH-RATE@KB/URL' at 20, @WINEMBED-BASE-SIZE@
-set label '@MOZILLA-GROWTH-RATE@KB/URL' at 20, @MOZILLA-BASE-SIZE@
-plot 'winEmbed-ws.dat' title 'Mem Usage (winEmbed)' with point 1,\
-     @WINEMBED-WS-LINE@ notitle with line 1,\
-     'winEmbed-pws.dat' title 'Peak Mem Usage (winEmbed)' with line 3,\
-     'mozilla-ws.dat' title 'Mem Usage (Mozilla)' with point 5,\
-     @MOZILLA-WS-LINE@ notitle with line 5,\
-     'mozilla-pws.dat' title 'Peak Mem Usage (Mozilla)' with line 7
deleted file mode 100644
--- a/tools/footprint/wm.cpp
+++ /dev/null
@@ -1,613 +0,0 @@
-/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * 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/. */
-
-/*
- * This program tracks a process's working memory usage using the
- * ``performance'' entries in the Win32 registry. It borrows from
- * the ``pviewer'' source code in the MS SDK.
- */
-
-#include <assert.h>
-#include <windows.h>
-#include <winperf.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define PN_PROCESS                          1
-#define PN_PROCESS_CPU                      2
-#define PN_PROCESS_PRIV                     3
-#define PN_PROCESS_USER                     4
-#define PN_PROCESS_WORKING_SET              5
-#define PN_PROCESS_PEAK_WS                  6
-#define PN_PROCESS_PRIO                     7
-#define PN_PROCESS_ELAPSE                   8
-#define PN_PROCESS_ID                       9
-#define PN_PROCESS_PRIVATE_PAGE            10
-#define PN_PROCESS_VIRTUAL_SIZE            11
-#define PN_PROCESS_PEAK_VS                 12
-#define PN_PROCESS_FAULT_COUNT             13
-#define PN_THREAD                          14
-#define PN_THREAD_CPU                      15
-#define PN_THREAD_PRIV                     16
-#define PN_THREAD_USER                     17
-#define PN_THREAD_START                    18
-#define PN_THREAD_SWITCHES                 19
-#define PN_THREAD_PRIO                     20
-#define PN_THREAD_BASE_PRIO                21
-#define PN_THREAD_ELAPSE                   22
-#define PN_THREAD_DETAILS                  23
-#define PN_THREAD_PC                       24
-#define PN_IMAGE                           25
-#define PN_IMAGE_NOACCESS                  26
-#define PN_IMAGE_READONLY                  27
-#define PN_IMAGE_READWRITE                 28
-#define PN_IMAGE_WRITECOPY                 29
-#define PN_IMAGE_EXECUTABLE                30
-#define PN_IMAGE_EXE_READONLY              31
-#define PN_IMAGE_EXE_READWRITE             32
-#define PN_IMAGE_EXE_WRITECOPY             33
-#define PN_PROCESS_ADDRESS_SPACE           34
-#define PN_PROCESS_PRIVATE_NOACCESS        35
-#define PN_PROCESS_PRIVATE_READONLY        36
-#define PN_PROCESS_PRIVATE_READWRITE       37
-#define PN_PROCESS_PRIVATE_WRITECOPY       38
-#define PN_PROCESS_PRIVATE_EXECUTABLE      39
-#define PN_PROCESS_PRIVATE_EXE_READONLY    40
-#define PN_PROCESS_PRIVATE_EXE_READWRITE   41
-#define PN_PROCESS_PRIVATE_EXE_WRITECOPY   42
-#define PN_PROCESS_MAPPED_NOACCESS         43
-#define PN_PROCESS_MAPPED_READONLY         44
-#define PN_PROCESS_MAPPED_READWRITE        45
-#define PN_PROCESS_MAPPED_WRITECOPY        46
-#define PN_PROCESS_MAPPED_EXECUTABLE       47
-#define PN_PROCESS_MAPPED_EXE_READONLY     48
-#define PN_PROCESS_MAPPED_EXE_READWRITE    49
-#define PN_PROCESS_MAPPED_EXE_WRITECOPY    50
-#define PN_PROCESS_IMAGE_NOACCESS          51
-#define PN_PROCESS_IMAGE_READONLY          52
-#define PN_PROCESS_IMAGE_READWRITE         53
-#define PN_PROCESS_IMAGE_WRITECOPY         54
-#define PN_PROCESS_IMAGE_EXECUTABLE        55
-#define PN_PROCESS_IMAGE_EXE_READONLY      56
-#define PN_PROCESS_IMAGE_EXE_READWRITE     57
-#define PN_PROCESS_IMAGE_EXE_WRITECOPY     58
-
-struct entry_t {
-    int   e_key;
-    int   e_index;
-    char* e_title;
-};
-
-entry_t entries[] = {
-{ PN_PROCESS,                          0, TEXT("Process") },
-{ PN_PROCESS_CPU,                      0, TEXT("% Processor Time") },
-{ PN_PROCESS_PRIV,                     0, TEXT("% Privileged Time") },
-{ PN_PROCESS_USER,                     0, TEXT("% User Time") },
-{ PN_PROCESS_WORKING_SET,              0, TEXT("Working Set") },
-{ PN_PROCESS_PEAK_WS,                  0, TEXT("Working Set Peak") },
-{ PN_PROCESS_PRIO,                     0, TEXT("Priority Base") },
-{ PN_PROCESS_ELAPSE,                   0, TEXT("Elapsed Time") },
-{ PN_PROCESS_ID,                       0, TEXT("ID Process") },
-{ PN_PROCESS_PRIVATE_PAGE,             0, TEXT("Private Bytes") },
-{ PN_PROCESS_VIRTUAL_SIZE,             0, TEXT("Virtual Bytes") },
-{ PN_PROCESS_PEAK_VS,                  0, TEXT("Virtual Bytes Peak") },
-{ PN_PROCESS_FAULT_COUNT,              0, TEXT("Page Faults/sec") },
-{ PN_THREAD,                           0, TEXT("Thread") },
-{ PN_THREAD_CPU,                       0, TEXT("% Processor Time") },
-{ PN_THREAD_PRIV,                      0, TEXT("% Privileged Time") },
-{ PN_THREAD_USER,                      0, TEXT("% User Time") },
-{ PN_THREAD_START,                     0, TEXT("Start Address") },
-{ PN_THREAD_SWITCHES,                  0, TEXT("Con0, TEXT Switches/sec") },
-{ PN_THREAD_PRIO,                      0, TEXT("Priority Current") },
-{ PN_THREAD_BASE_PRIO,                 0, TEXT("Priority Base") },
-{ PN_THREAD_ELAPSE,                    0, TEXT("Elapsed Time") },
-{ PN_THREAD_DETAILS,                   0, TEXT("Thread Details") },
-{ PN_THREAD_PC,                        0, TEXT("User PC") },
-{ PN_IMAGE,                            0, TEXT("Image") },
-{ PN_IMAGE_NOACCESS,                   0, TEXT("No Access") },
-{ PN_IMAGE_READONLY,                   0, TEXT("Read Only") },
-{ PN_IMAGE_READWRITE,                  0, TEXT("Read/Write") },
-{ PN_IMAGE_WRITECOPY,                  0, TEXT("Write Copy") },
-{ PN_IMAGE_EXECUTABLE,                 0, TEXT("Executable") },
-{ PN_IMAGE_EXE_READONLY,               0, TEXT("Exec Read Only") },
-{ PN_IMAGE_EXE_READWRITE,              0, TEXT("Exec Read/Write") },
-{ PN_IMAGE_EXE_WRITECOPY,              0, TEXT("Exec Write Copy") },
-{ PN_PROCESS_ADDRESS_SPACE,            0, TEXT("Process Address Space") },
-{ PN_PROCESS_PRIVATE_NOACCESS,         0, TEXT("Reserved Space No Access") },
-{ PN_PROCESS_PRIVATE_READONLY,         0, TEXT("Reserved Space Read Only") },
-{ PN_PROCESS_PRIVATE_READWRITE,        0, TEXT("Reserved Space Read/Write") },
-{ PN_PROCESS_PRIVATE_WRITECOPY,        0, TEXT("Reserved Space Write Copy") },
-{ PN_PROCESS_PRIVATE_EXECUTABLE,       0, TEXT("Reserved Space Executable") },
-{ PN_PROCESS_PRIVATE_EXE_READONLY,     0, TEXT("Reserved Space Exec Read Only") },
-{ PN_PROCESS_PRIVATE_EXE_READWRITE,    0, TEXT("Reserved Space Exec Read/Write") },
-{ PN_PROCESS_PRIVATE_EXE_WRITECOPY,    0, TEXT("Reserved Space Exec Write Copy") },
-{ PN_PROCESS_MAPPED_NOACCESS,          0, TEXT("Mapped Space No Access") },
-{ PN_PROCESS_MAPPED_READONLY,          0, TEXT("Mapped Space Read Only") },
-{ PN_PROCESS_MAPPED_READWRITE,         0, TEXT("Mapped Space Read/Write") },
-{ PN_PROCESS_MAPPED_WRITECOPY,         0, TEXT("Mapped Space Write Copy") },
-{ PN_PROCESS_MAPPED_EXECUTABLE,        0, TEXT("Mapped Space Executable") },
-{ PN_PROCESS_MAPPED_EXE_READONLY,      0, TEXT("Mapped Space Exec Read Only") },
-{ PN_PROCESS_MAPPED_EXE_READWRITE,     0, TEXT("Mapped Space Exec Read/Write") },
-{ PN_PROCESS_MAPPED_EXE_WRITECOPY,     0, TEXT("Mapped Space Exec Write Copy") },
-{ PN_PROCESS_IMAGE_NOACCESS,           0, TEXT("Image Space No Access") },
-{ PN_PROCESS_IMAGE_READONLY,           0, TEXT("Image Space Read Only") },
-{ PN_PROCESS_IMAGE_READWRITE,          0, TEXT("Image Space Read/Write") },
-{ PN_PROCESS_IMAGE_WRITECOPY,          0, TEXT("Image Space Write Copy") },
-{ PN_PROCESS_IMAGE_EXECUTABLE,         0, TEXT("Image Space Executable") },
-{ PN_PROCESS_IMAGE_EXE_READONLY,       0, TEXT("Image Space Exec Read Only") },
-{ PN_PROCESS_IMAGE_EXE_READWRITE,      0, TEXT("Image Space Exec Read/Write") },
-{ PN_PROCESS_IMAGE_EXE_WRITECOPY,      0, TEXT("Image Space Exec Write Copy") },
-{ 0,                                   0, 0 },
-};
-
-#define NENTRIES ((sizeof(entries) / sizeof(entry_t)) - 1)
-
-static int
-key_for_index(int key)
-{
-    entry_t* entry = entries + NENTRIES / 2;
-    unsigned int step = 64 / 4; // XXX
-
-    while (step) {
-        if (key < entry->e_key)
-            entry -= step;
-        else if (key > entry->e_key)
-            entry += step;
-
-        if (key == entry->e_key)
-            return entry->e_index;
-
-        step >>= 1;
-    }
-
-    assert(false);
-    return 0;
-}
-
-
-class auto_hkey {
-protected:
-    HKEY hkey;
-
-    HKEY* begin_assignment() {
-        if (hkey) {
-            ::RegCloseKey(hkey);
-            hkey = 0;
-        }
-        return &hkey;
-    }
-
-public:
-    auto_hkey() : hkey(0) {}
-    ~auto_hkey() { ::RegCloseKey(hkey); }
-    
-    HKEY get() const { return hkey; }
-    operator HKEY() const { return get(); }
-
-    friend HKEY*
-    getter_Acquires(auto_hkey& hkey);
-};
-
-static HKEY*
-getter_Acquires(auto_hkey& hkey)
-{
-    return hkey.begin_assignment();
-}
-
-
-static int
-get_perf_titles(char*& buffer, char**& titles, int& last_title_index)
-{
-    DWORD result;
-
-    // Open the perflib key to find out the last counter's index and
-    // system version.
-    auto_hkey perflib_hkey;
-    result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                            TEXT("software\\microsoft\\windows nt\\currentversion\\perflib"),
-                            0,
-                            KEY_READ,
-                            getter_Acquires(perflib_hkey));
-
-    if (result != ERROR_SUCCESS)
-        return result;
-
-    // Get the last counter's index so we know how much memory to
-    // allocate for titles
-    DWORD data_size = sizeof(DWORD);
-    DWORD type;
-    result = ::RegQueryValueEx(perflib_hkey,
-                               TEXT("Last Counter"),
-                               0,
-                               &type,
-                               reinterpret_cast<BYTE*>(&last_title_index),
-                               &data_size);
-
-    if (result != ERROR_SUCCESS)
-        return result;
-
-    // Find system version, for system earlier than 1.0a, there's no
-    // version value.
-    int version;
-    result = ::RegQueryValueEx(perflib_hkey,
-                               TEXT("Version"),
-                               0,
-                               &type,
-                               reinterpret_cast<BYTE*>(&version),
-                               &data_size);
-
-    bool is_nt_10 = (result == ERROR_SUCCESS);
-
-    // Now, get ready for the counter names and indexes.
-    char* counter_value_name;
-    auto_hkey counter_autohkey;
-    HKEY counter_hkey;
-    if (is_nt_10) {
-        // NT 1.0, so make hKey2 point to ...\perflib\009 and get
-        //  the counters from value "Counters"
-        counter_value_name = TEXT("Counters");
-        result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                                TEXT("software\\microsoft\\windows nt\\currentversion\\perflib\\009"),
-                                0,
-                                KEY_READ,
-                                getter_Acquires(counter_autohkey));
-
-        if (result != ERROR_SUCCESS)
-            return result;
-
-        counter_hkey = counter_autohkey;
-    }
-    else {
-        // NT 1.0a or later.  Get the counters in key HKEY_PERFORMANCE_KEY
-        //  and from value "Counter 009"
-        counter_value_name = TEXT("Counter 009");
-        counter_hkey = HKEY_PERFORMANCE_DATA;
-    }
-
-    // Find out the size of the data.
-    result = ::RegQueryValueEx(counter_hkey,
-                               counter_value_name,
-                               0,
-                               &type,
-                               0,
-                               &data_size);
-
-    if (result != ERROR_SUCCESS)
-        return result;
-
-    // Allocate memory
-    buffer = new char[data_size];
-    titles = new char*[last_title_index + 1];
-    for (int i = 0; i <= last_title_index; ++i)
-        titles[i] = 0;
-
-    // Query the data
-    result = ::RegQueryValueEx(counter_hkey,
-                               counter_value_name,
-                               0,
-                               &type,
-                               reinterpret_cast<BYTE*>(buffer),
-                               &data_size);
-    if (result != ERROR_SUCCESS)
-        return result;
-
-    // Setup the titles array of pointers to point to beginning of
-    // each title string.
-    char* title = buffer;
-    int len;
-
-    while (len = lstrlen(title)) {
-        int index = atoi(title);
-        title += len + 1;
-
-        if (index <= last_title_index)
-            titles[index] = title;
-
-#ifdef DEBUG
-        printf("%d=%s\n", index, title);
-#endif
-
-        title += lstrlen(title) + 1;
-    }
-
-    return ERROR_SUCCESS;
-}
-
-static void
-init_entries()
-{
-    char* buffer;
-    char** titles;
-    int last = 0;
-
-    DWORD result = get_perf_titles(buffer, titles, last);
-
-    assert(result == ERROR_SUCCESS);
-
-    for (entry_t* entry = entries; entry->e_key != 0; ++entry) {
-        for (int index = 0; index <= last; ++index) {
-            if (titles[index] && 0 == lstrcmpi(titles[index], entry->e_title)) {
-                entry->e_index = index;
-                break;
-            }
-        }
-
-        if (entry->e_index == 0) {
-            fprintf(stderr, "warning: unable to find index for ``%s''\n", entry->e_title);
-        }
-    }
-
-    delete[] buffer;
-    delete[] titles;
-}
-
-
-
-static DWORD
-get_perf_data(HKEY perf_hkey, char* object_index, PERF_DATA_BLOCK** data, DWORD* size)
-{
-    if (! *data)
-        *data = reinterpret_cast<PERF_DATA_BLOCK*>(new char[*size]);
-
-    DWORD result;
-
-    while (1) {
-        DWORD type;
-        DWORD real_size = *size;
-
-        result = ::RegQueryValueEx(perf_hkey,
-                                   object_index,
-                                   0,
-                                   &type,
-                                   reinterpret_cast<BYTE*>(*data),
-                                   &real_size);
-
-        if (result != ERROR_MORE_DATA)
-            break;
-
-        delete[] *data;
-        *size += 1024;
-        *data = reinterpret_cast<PERF_DATA_BLOCK*>(new char[*size]);
-
-        if (! *data)
-            return ERROR_NOT_ENOUGH_MEMORY;
-    }
-
-    return result;
-}
-
-
-static const PERF_OBJECT_TYPE*
-first_object(const PERF_DATA_BLOCK* data)
-{
-    return data
-        ? reinterpret_cast<const PERF_OBJECT_TYPE*>(reinterpret_cast<const char*>(data) + data->HeaderLength)
-        : 0;
-}
-
-static const PERF_OBJECT_TYPE*
-next_object(const PERF_OBJECT_TYPE* object)
-{
-    return object
-        ? reinterpret_cast<const PERF_OBJECT_TYPE*>(reinterpret_cast<const char*>(object) + object->TotalByteLength)
-        : 0;
-}
-
-const PERF_OBJECT_TYPE*
-find_object(const PERF_DATA_BLOCK* data, DWORD index)
-{
-    const PERF_OBJECT_TYPE* object = first_object(data);
-    if (! object)
-        return 0;
-
-    for (int i = 0; i < data->NumObjectTypes; ++i) {
-        if (object->ObjectNameTitleIndex == index)
-            return object;
-
-        object = next_object(object);
-    }
-
-    return 0;
-}
-
-
-static const PERF_COUNTER_DEFINITION*
-first_counter(const PERF_OBJECT_TYPE* object)
-{
-    return object
-        ? reinterpret_cast<const PERF_COUNTER_DEFINITION*>(reinterpret_cast<const char*>(object) + object->HeaderLength)
-        : 0;
-}
-
-static const PERF_COUNTER_DEFINITION*
-next_counter(const PERF_COUNTER_DEFINITION* counter)
-{
-    return counter ?
-        reinterpret_cast<const PERF_COUNTER_DEFINITION*>(reinterpret_cast<const char*>(counter) + counter->ByteLength)
-        : 0;
-}
-
-
-static const PERF_COUNTER_DEFINITION*
-find_counter(const PERF_OBJECT_TYPE* object, int index)
-{
-    const PERF_COUNTER_DEFINITION* counter =
-        first_counter(object);
-
-    if (! counter)
-        return 0;
-
-    for (int i; i < object->NumCounters; ++i) {
-        if (counter->CounterNameTitleIndex == index)
-            return counter;
-
-        counter = next_counter(counter);
-    }
-
-    return 0;
-}
-
-
-static const PERF_INSTANCE_DEFINITION*
-first_instance(const PERF_OBJECT_TYPE* object)
-{
-    return object
-        ? reinterpret_cast<const PERF_INSTANCE_DEFINITION*>(reinterpret_cast<const char*>(object) + object->DefinitionLength)
-        : 0;
-}
-
-
-static const PERF_INSTANCE_DEFINITION*
-next_instance(const PERF_INSTANCE_DEFINITION* instance)
-{
-    if (instance) {
-        const PERF_COUNTER_BLOCK* counter_block =
-            reinterpret_cast<const PERF_COUNTER_BLOCK*>(reinterpret_cast<const char*>(instance) + instance->ByteLength);
-
-        return reinterpret_cast<const PERF_INSTANCE_DEFINITION*>(reinterpret_cast<const char*>(counter_block) + counter_block->ByteLength);
-    }
-    else {
-        return 0;
-    }
-}
-
-
-static const wchar_t*
-instance_name(const PERF_INSTANCE_DEFINITION* instance)
-{
-    return instance
-        ? reinterpret_cast<const wchar_t*>(reinterpret_cast<const char*>(instance) + instance->NameOffset)
-        : 0;
-}
-
-
-static const void*
-counter_data(const PERF_INSTANCE_DEFINITION* instance,
-             const PERF_COUNTER_DEFINITION* counter)
-{
-    if (counter && instance) {
-        const PERF_COUNTER_BLOCK* counter_block; 
-        counter_block = reinterpret_cast<const PERF_COUNTER_BLOCK*>(reinterpret_cast<const char*>(instance) + instance->ByteLength);
-        return reinterpret_cast<const char*>(counter_block) + counter->CounterOffset;
-    }
-    else {
-        return 0;
-    }
-}
-
-
-static bool
-list_process(PERF_DATA_BLOCK* perf_data, wchar_t* process_name)
-{
-    const PERF_OBJECT_TYPE* process = find_object(perf_data, key_for_index(PN_PROCESS));
-    const PERF_COUNTER_DEFINITION* working_set      = find_counter(process, key_for_index(PN_PROCESS_WORKING_SET));
-    const PERF_COUNTER_DEFINITION* peak_working_set = find_counter(process, key_for_index(PN_PROCESS_PEAK_WS));
-    const PERF_COUNTER_DEFINITION* private_page     = find_counter(process, key_for_index(PN_PROCESS_PRIVATE_PAGE));
-    const PERF_COUNTER_DEFINITION* virtual_size     = find_counter(process, key_for_index(PN_PROCESS_VIRTUAL_SIZE));
-
-    const PERF_INSTANCE_DEFINITION* instance = first_instance(process);
-    int index = 0;
-
-    bool found = false;
-
-    while (instance && index < process->NumInstances) {
-        const wchar_t* name = instance_name(instance);
-        if (lstrcmpW(process_name, name) == 0) {
-            printf("%d %d %d %d\n",
-                   *(static_cast<const int*>(counter_data(instance, working_set))),
-                   *(static_cast<const int*>(counter_data(instance, peak_working_set))),
-                   *(static_cast<const int*>(counter_data(instance, private_page))),
-                   *(static_cast<const int*>(counter_data(instance, virtual_size))));
-
-            found = true;
-        }
-
-        instance = next_instance(instance);
-        ++index;
-    }
-
-    if (found) {
-#if 0
-        // Dig up address space data.
-        PERF_OBJECT_TYPE* address_space = FindObject(costly_data, PX_PROCESS_ADDRESS_SPACE);
-        PERF_COUNTER_DEFINITION* image_executable = FindCounter(process, PX_PROCESS_IMAGE_EXECUTABLE);
-        PERF_COUNTER_DEFINITION* image_exe_readonly = FindCounter(process, PX_PROCESS_IMAGE_EXE_READONLY);
-        PERF_COUNTER_DEFINITION* image_exe_readwrite = FindCounter(process, PX_PROCESS_IMAGE_EXE_READWRITE);
-        PERF_COUNTER_DEFINITION* image_exe_writecopy = FindCounter(process, PX_PROCESS_IMAGE_EXE_WRITECOPY);
-#endif
-    }
-
-    return found;
-}
-
-
-int
-main(int argc, char* argv[])
-{
-    wchar_t process_name[32];
-
-    int interval = 10000; // msec
-
-    int i = 0;
-    while (++i < argc) {
-        if (argv[i][0] != '-')
-            break;
-
-        switch (argv[i][1]) {
-        case 'i':
-            interval = atoi(argv[++i]) * 1000;
-            break;
-            
-        default:
-            fprintf(stderr, "unknown option `%c'\n", argv[i][1]);
-            exit(1);
-        }
-    }
-
-    if (argv[i]) {
-        char* p = argv[i];
-        wchar_t* q = process_name;
-        while (*q++ = wchar_t(*p++))
-            continue;
-    }
-    else {
-        fprintf(stderr, "no image name specified\n");
-        exit(1);
-    }
-
-    init_entries();
-
-    PERF_DATA_BLOCK* perf_data = 0;
-    PERF_DATA_BLOCK* costly_data = 0;
-    DWORD perf_data_size = 50 * 1024;
-    DWORD costly_data_size = 100 * 1024;
-
-    do {
-        char buf[64];
-        sprintf(buf, "%ld %ld",
-                key_for_index(PN_PROCESS),
-                key_for_index(PN_THREAD));
-
-        get_perf_data(HKEY_PERFORMANCE_DATA, buf, &perf_data, &perf_data_size);
-
-#if 0
-        sprintf(buf, "%ld %ld %ld",
-                key_for_index(PN_PROCESS_ADDRESS_SPACE),
-                key_for_index(PN_IMAGE),
-                key_for_index(PN_THREAD_DETAILS));
-
-        get_perf_data(HKEY_PERFORMANCE_DATA, buf, &costly_data, &costly_data_size);
-#endif
-
-        if (! list_process(perf_data, process_name))
-            break;
-
-        _sleep(interval);
-    } while (1);
-
-    return 0;
-}
-
rename from tools/footprint/leak-gauge.html
rename to tools/leak-gauge/leak-gauge.html
rename from tools/footprint/leak-gauge.pl
rename to tools/leak-gauge/leak-gauge.pl
--- a/xpcom/tests/TestHarness.h
+++ b/xpcom/tests/TestHarness.h
@@ -7,24 +7,16 @@
  * Test harness for XPCOM objects, providing a scoped XPCOM initializer,
  * nsCOMPtr, nsRefPtr, do_CreateInstance, do_GetService, ns(Auto|C|)String,
  * and stdio.h/stdlib.h.
  */
 
 #ifndef TestHarness_h__
 #define TestHarness_h__
 
-#if defined(_MSC_VER) && defined(MOZ_STATIC_JS)
-/*
- * Including js/OldDebugAPI.h may cause build break with --disable-shared-js
- * This is a workaround for bug 673616.
- */
-#define STATIC_JS_API
-#endif
-
 #include "mozilla/ArrayUtils.h"
 
 #include "prenv.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsStringGlue.h"
--- a/xpcom/threads/ThreadStackHelper.cpp
+++ b/xpcom/threads/ThreadStackHelper.cpp
@@ -9,18 +9,16 @@
 #include "nsJSPrincipals.h"
 #include "nsScriptSecurityManager.h"
 #include "jsfriendapi.h"
 #include "prprf.h"
 #ifdef MOZ_THREADSTACKHELPER_NATIVE
 #include "shared-libraries.h"
 #endif
 
-#include "js/OldDebugAPI.h"
-
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Move.h"
 #include "mozilla/Scoped.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/MemoryChecking.h"