Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 30 Oct 2014 16:03:53 -0400
changeset 213208 e0b505a37b1c0bdeb1fd9523a49eb36b58d2133d
parent 213158 9e2062306f6279283b5260ee7c71fe7e62d4c340 (current diff)
parent 213207 1955735d5cdc1e133e99ff1d5861053321a09d53 (diff)
child 213209 af6379f6436fa3ed44efa0167edda95925367bd1
child 213239 bc78d64a2a148dd236cadec6e9d6ad1d1c8cd81a
child 213261 b0cde5e6059a1acadc9e1e9b80e083382d37252d
push id27742
push userryanvm@gmail.com
push dateThu, 30 Oct 2014 20:15:35 +0000
treeherdermozilla-central@e0b505a37b1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
first release with
nightly linux32
e0b505a37b1c / 36.0a1 / 20141031030201 / files
nightly linux64
e0b505a37b1c / 36.0a1 / 20141031030201 / files
nightly mac
e0b505a37b1c / 36.0a1 / 20141031030201 / files
nightly win32
e0b505a37b1c / 36.0a1 / 20141031030201 / files
nightly win64
e0b505a37b1c / 36.0a1 / 20141031030201 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
dom/system/gonk/GonkGPSGeolocationProvider.cpp
modules/libpref/init/all.js
security/manager/ssl/tests/unit/test_ev_certs/cert8.db
security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12
security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12
security/manager/ssl/tests/unit/test_ev_certs/key3.db
security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -1371,17 +1371,18 @@ Accessible::ARIATransformRole(role aRole
       return roles::BUTTONMENU;
     }
 
   } else if (aRole == roles::LISTBOX) {
     // A listbox inside of a combobox needs a special role because of ATK
     // mapping to menu.
     if (mParent && mParent->Role() == roles::COMBOBOX) {
       return roles::COMBOBOX_LIST;
-
+    } else {
+      // Listbox is owned by a combobox
       Relation rel = RelationByType(RelationType::NODE_CHILD_OF);
       Accessible* targetAcc = nullptr;
       while ((targetAcc = rel.Next()))
         if (targetAcc->Role() == roles::COMBOBOX)
           return roles::COMBOBOX_LIST;
     }
 
   } else if (aRole == roles::OPTION) {
--- a/accessible/tests/mochitest/role/test_general.html
+++ b/accessible/tests/mochitest/role/test_general.html
@@ -66,16 +66,20 @@
       testRole("definitionterm", ROLE_TERM);
       testRole("definitiondescription", ROLE_DEFINITION);
 
       // Has click, mousedown or mouseup listeners.
       testRole("span1", ROLE_TEXT_CONTAINER);
       testRole("span2", ROLE_TEXT_CONTAINER);
       testRole("span3", ROLE_TEXT_CONTAINER);
 
+      // Test role of listbox inside combobox
+      testRole("listbox1", ROLE_COMBOBOX_LIST);
+      testRole("listbox2", ROLE_COMBOBOX_LIST);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
 <body>
@@ -113,16 +117,21 @@
      title="Map section to pane (like role=region)">
     Mozilla Bug 614310
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=734982"
      title="Map ARIA role FORM">
     Bug 734982
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1044431"
+     title="Listbox owned by combobox has the wrong role">
+    Mozilla Bug 1044431
+  </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <form id="frm" action="submit.php" method="post">
     <label for="data">File</label>:
@@ -162,10 +171,16 @@
   <dl id="definitionlist">
   <dt id="definitionterm">gecko</dt>
   <dd id="definitiondescription">geckos have sticky toes</dd>
   </dl>
 
   <span id="span1" onclick="">clickable span</span>
   <span id="span2" onmousedown="">clickable span</span>
   <span id="span3" onmouseup="">clickable span</span>
+
+  <div id="combobox1" role="combobox">
+    <div id="listbox1" role="listbox"></div>
+  </div>
+  <div id="combobox2" role="combobox" aria-owns="listbox2"></div>
+  <div id="listbox2" role="listbox"></div>
 </body>
 </html>
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -1624,17 +1624,17 @@ public:
   explicit PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate)
     : WorkerMainThreadRunnable(aWorkerPrivate)
     , mEnabled(false)
   { }
 
   bool MainThreadRun() MOZ_OVERRIDE
   {
     AssertIsOnMainThread();
-    mEnabled = WebSocket::PrefEnabled(nullptr, nullptr);
+    mEnabled = Preferences::GetBool("dom.workers.websocket.enabled", false);
     return true;
   }
 
   bool IsEnabled() const
   {
     return mEnabled;
   }
 
@@ -1642,29 +1642,30 @@ private:
   bool mEnabled;
 };
 
 } // anonymous namespace
 
 bool
 WebSocket::PrefEnabled(JSContext* /* aCx */, JSObject* /* aGlobal */)
 {
+  // WebSockets are always enabled on main-thread.
   if (NS_IsMainThread()) {
-    return Preferences::GetBool("network.websocket.enabled", true);
-  } else {
-    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
-    MOZ_ASSERT(workerPrivate);
-    workerPrivate->AssertIsOnWorkerThread();
-
-    nsRefPtr<PrefEnabledRunnable> runnable =
-      new PrefEnabledRunnable(workerPrivate);
-    runnable->Dispatch(workerPrivate->GetJSContext());
-
-    return runnable->IsEnabled();
+    return true;
   }
+
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+  workerPrivate->AssertIsOnWorkerThread();
+
+  nsRefPtr<PrefEnabledRunnable> runnable =
+    new PrefEnabledRunnable(workerPrivate);
+  runnable->Dispatch(workerPrivate->GetJSContext());
+
+  return runnable->IsEnabled();
 }
 
 nsresult
 WebSocketImpl::ParseURL(const nsAString& aURL)
 {
   AssertIsOnMainThread();
   NS_ENSURE_TRUE(!aURL.IsEmpty(), NS_ERROR_DOM_SYNTAX_ERR);
 
--- a/dom/bindings/ToJSValue.cpp
+++ b/dom/bindings/ToJSValue.cpp
@@ -55,10 +55,24 @@ bool
 ToJSValue(JSContext* aCx,
           nsresult aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   nsRefPtr<Exception> exception = CreateException(aCx, aArgument);
   return ToJSValue(aCx, exception, aValue);
 }
 
+bool
+ToJSValue(JSContext* aCx,
+          ErrorResult& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  MOZ_ASSERT(aArgument.Failed());
+  ThrowMethodFailedWithDetails(aCx, aArgument, "", "");
+  if (!JS_GetPendingException(aCx, aValue)) {
+    return false;
+  }
+  JS_ClearPendingException(aCx);
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -256,16 +256,24 @@ ToJSValue(JSContext* aCx, const JS::Root
 
 // Accept nsresult, for use in rejections, and create an XPCOM
 // exception object representing that nsresult.
 bool
 ToJSValue(JSContext* aCx,
           nsresult aArgument,
           JS::MutableHandle<JS::Value> aValue);
 
+// Accept ErrorResult, for use in rejections, and create an exception
+// representing the failure.  Note, the ErrorResult must indicate a failure
+// with aArgument.Failure() returning true.
+bool
+ToJSValue(JSContext* aCx,
+          ErrorResult& aArgument,
+          JS::MutableHandle<JS::Value> aValue);
+
 // Accept pointers to other things we accept
 template <typename T>
 typename EnableIf<IsPointer<T>::value, bool>::Type
 ToJSValue(JSContext* aCx,
           T aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   return ToJSValue(aCx, *aArgument, aValue);
--- a/dom/canvas/CanvasImageCache.cpp
+++ b/dom/canvas/CanvasImageCache.cpp
@@ -77,16 +77,46 @@ public:
   {
     return HashGeneric(key->mImage, key->mCanvas);
   }
   enum { ALLOW_MEMMOVE = true };
 
   nsAutoPtr<ImageCacheEntryData> mData;
 };
 
+class SimpleImageCacheEntry : public PLDHashEntryHdr {
+public:
+  typedef imgIRequest& KeyType;
+  typedef const imgIRequest* KeyTypePointer;
+
+  explicit SimpleImageCacheEntry(KeyTypePointer aKey)
+    : mRequest(const_cast<imgIRequest*>(aKey))
+  {}
+  SimpleImageCacheEntry(const SimpleImageCacheEntry &toCopy)
+    : mRequest(toCopy.mRequest)
+    , mSourceSurface(toCopy.mSourceSurface)
+  {}
+  ~SimpleImageCacheEntry() {}
+
+  bool KeyEquals(KeyTypePointer key) const
+  {
+    return key == mRequest;
+  }
+
+  static KeyTypePointer KeyToPointer(KeyType key) { return &key; }
+  static PLDHashNumber HashKey(KeyTypePointer key)
+  {
+    return NS_PTR_TO_UINT32(key) >> 2;
+  }
+  enum { ALLOW_MEMMOVE = true };
+
+  nsCOMPtr<imgIRequest> mRequest;
+  RefPtr<SourceSurface> mSourceSurface;
+};
+
 static bool sPrefsInitialized = false;
 static int32_t sCanvasImageCacheLimit = 0;
 
 class ImageCacheObserver;
 
 class ImageCache MOZ_FINAL : public nsExpirationTracker<ImageCacheEntryData,4> {
 public:
   // We use 3 generations of 1 second each to get a 2-3 seconds timeout.
@@ -94,20 +124,22 @@ public:
   ImageCache();
   ~ImageCache();
 
   virtual void NotifyExpired(ImageCacheEntryData* aObject)
   {
     mTotal -= aObject->SizeInBytes();
     RemoveObject(aObject);
     // Deleting the entry will delete aObject since the entry owns aObject
+    mSimpleCache.RemoveEntry(*aObject->mRequest);
     mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas));
   }
 
   nsTHashtable<ImageCacheEntry> mCache;
+  nsTHashtable<SimpleImageCacheEntry> mSimpleCache;
   size_t mTotal;
   nsRefPtr<ImageCacheObserver> mImageCacheObserver;
 };
 
 static ImageCache* gImageCache = nullptr;
 
 // Listen memory-pressure event for image cache purge
 class ImageCacheObserver MOZ_FINAL : public nsIObserver
@@ -225,16 +257,22 @@ CanvasImageCache::NotifyDrawImage(Elemen
       ilc->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                       getter_AddRefs(entry->mData->mRequest));
     }
     entry->mData->mILC = ilc;
     entry->mData->mSourceSurface = aSource;
     entry->mData->mSize = aSize;
 
     gImageCache->mTotal += entry->mData->SizeInBytes();
+
+    if (entry->mData->mRequest) {
+      SimpleImageCacheEntry* simpleentry =
+        gImageCache->mSimpleCache.PutEntry(*entry->mData->mRequest);
+      simpleentry->mSourceSurface = aSource;
+    }
   }
 
   if (!sCanvasImageCacheLimit)
     return;
 
   // Expire the image cache early if its larger than we want it to be.
   while (gImageCache->mTotal > size_t(sCanvasImageCacheLimit))
     gImageCache->AgeOneGeneration();
@@ -258,16 +296,39 @@ CanvasImageCache::Lookup(Element* aImage
     return nullptr;
 
   gImageCache->MarkUsed(entry->mData);
 
   *aSize = entry->mData->mSize;
   return entry->mData->mSourceSurface;
 }
 
+SourceSurface*
+CanvasImageCache::SimpleLookup(Element* aImage)
+{
+  if (!gImageCache)
+    return nullptr;
+
+  nsCOMPtr<imgIRequest> request;
+  nsCOMPtr<nsIImageLoadingContent> ilc = do_QueryInterface(aImage);
+  if (!ilc)
+    return nullptr;
+
+  ilc->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
+                  getter_AddRefs(request));
+  if (!request)
+    return nullptr;
+
+  SimpleImageCacheEntry* entry = gImageCache->mSimpleCache.GetEntry(*request);
+  if (!entry)
+    return nullptr;
+
+  return entry->mSourceSurface;
+}
+
 NS_IMPL_ISUPPORTS(CanvasImageCacheShutdownObserver, nsIObserver)
 
 NS_IMETHODIMP
 CanvasImageCacheShutdownObserver::Observe(nsISupports *aSubject,
                                           const char *aTopic,
                                           const char16_t *aData)
 {
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
--- a/dom/canvas/CanvasImageCache.h
+++ b/dom/canvas/CanvasImageCache.h
@@ -39,13 +39,20 @@ public:
    * Check whether aImage has recently been drawn into aCanvas. If we return
    * a non-null surface, then the image was recently drawn into the canvas
    * (with the same image request) and the returned surface contains the image
    * data, and the image size will be returned in aSize.
    */
   static SourceSurface* Lookup(dom::Element* aImage,
                                dom::HTMLCanvasElement* aCanvas,
                                gfxIntSize* aSize);
+
+  /**
+   * This is the same as Lookup, except it works on any image recently drawn
+   * into any canvas. Security checks need to be done again if using the
+   * results from this.
+   */
+  static SourceSurface* SimpleLookup(dom::Element* aImage);
 };
 
 }
 
 #endif /* CANVASIMAGECACHE_H_ */
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3875,16 +3875,66 @@ ExtractSubrect(SourceSurface* aSurface, 
   }
 
   *aSourceRect -= roundedOutSourceRect.TopLeft();
 
   subrectDT->CopySurface(aSurface, roundedOutSourceRectInt, IntPoint());
   return subrectDT->Snapshot();
 }
 
+// Acts like nsLayoutUtils::SurfaceFromElement, but it'll attempt
+// to pull a SourceSurface from our cache. This allows us to avoid
+// reoptimizing surfaces if content and canvas backends are different.
+nsLayoutUtils::SurfaceFromElementResult
+CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement)
+{
+  nsLayoutUtils::SurfaceFromElementResult res;
+
+  nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aElement);
+  if (!imageLoader) {
+    return res;
+  }
+
+  nsCOMPtr<imgIRequest> imgRequest;
+  imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
+                          getter_AddRefs(imgRequest));
+  if (!imgRequest) {
+    return res;
+  }
+
+  uint32_t status;
+  if (NS_FAILED(imgRequest->GetImageStatus(&status)) ||
+      !(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
+    return res;
+  }
+
+  nsCOMPtr<nsIPrincipal> principal;
+  if (NS_FAILED(imgRequest->GetImagePrincipal(getter_AddRefs(principal))) ||
+      !principal) {
+    return res;
+  }
+
+  res.mSourceSurface = CanvasImageCache::SimpleLookup(aElement);
+  if (!res.mSourceSurface) {
+    return res;
+  }
+
+  int32_t corsmode = imgIRequest::CORS_NONE;
+  if (NS_SUCCEEDED(imgRequest->GetCORSMode(&corsmode))) {
+    res.mCORSUsed = corsmode != imgIRequest::CORS_NONE;
+  }
+
+  res.mSize = ThebesIntSize(res.mSourceSurface->GetSize());
+  res.mPrincipal = principal.forget();
+  res.mIsWriteOnly = false;
+  res.mImageRequest = imgRequest.forget();
+
+  return res;
+}
+
 //
 // image
 //
 
 // drawImage(in HTMLImageElement image, in float dx, in float dy);
 //   -- render image from 0,0 at dx,dy top-left coords
 // drawImage(in HTMLImageElement image, in float dx, in float dy, in float sw, in float sh);
 //   -- render image from 0,0 at dx,dy top-left coords clipping it to sw,sh
@@ -3935,18 +3985,25 @@ CanvasRenderingContext2D::DrawImage(cons
 
   nsLayoutUtils::DirectDrawInfo drawInfo;
 
   if (!srcSurf) {
     // The canvas spec says that drawImage should draw the first frame
     // of animated images. We also don't want to rasterize vector images.
     uint32_t sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME |
                         nsLayoutUtils::SFE_NO_RASTERIZING_VECTORS;
+    // The cache lookup can miss even if the image is already in the cache
+    // if the image is coming from a different element or cached for a
+    // different canvas. This covers the case when we miss due to caching
+    // for a different canvas, but CanvasImageCache should be fixed if we
+    // see misses due to different elements drawing the same image.
     nsLayoutUtils::SurfaceFromElementResult res =
-      nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget);
+      CachedSurfaceFromElement(element);
+    if (!res.mSourceSurface)
+      res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget);
 
     if (!res.mSourceSurface && !res.mDrawInfo.mImgContainer) {
       // Spec says to silently do nothing if the element is still loading.
       if (!res.mIsStillLoading) {
         error.Throw(NS_ERROR_NOT_AVAILABLE);
       }
       return;
     }
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -709,16 +709,19 @@ protected:
   mozilla::gfx::SurfaceFormat GetSurfaceFormat() const;
 
   /**
    * Update CurrentState().filter with the filter description for
    * CurrentState().filterChain.
    */
   void UpdateFilter();
 
+  nsLayoutUtils::SurfaceFromElementResult
+    CachedSurfaceFromElement(Element* aElement);
+
   void DrawImage(const HTMLImageOrCanvasOrVideoElement &imgElt,
                  double sx, double sy, double sw, double sh,
                  double dx, double dy, double dw, double dh,
                  uint8_t optional_argc, mozilla::ErrorResult& error);
 
   void DrawDirectlyToCanvas(const nsLayoutUtils::DirectDrawInfo& image,
                             mozilla::gfx::Rect* bounds,
                             mozilla::gfx::Rect dest,
--- a/dom/contacts/tests/mochitest.ini
+++ b/dom/contacts/tests/mochitest.ini
@@ -1,12 +1,12 @@
 [DEFAULT]
 skip-if = e10s
+support-files = shared.js
 
-[shared.js]
 [test_contacts_basics.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_contacts_basics2.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_contacts_blobs.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_contacts_events.html]
 [test_contacts_getall.html]
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -524,16 +524,21 @@ EventStateManager::PreHandleEvent(nsPres
     ++gMouseOrKeyboardEventCounter;
   }
 
   *aStatus = nsEventStatus_eIgnore;
 
   WheelTransaction::OnEvent(aEvent);
 
   switch (aEvent->message) {
+  case NS_CONTEXTMENU:
+    if (sIsPointerLocked) {
+      return NS_ERROR_DOM_INVALID_STATE_ERR;
+    }
+    break;
   case NS_MOUSE_BUTTON_DOWN: {
     switch (mouseEvent->button) {
     case WidgetMouseEvent::eLeftButton:
       BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
       mLClickCount = mouseEvent->clickCount;
       SetClickCount(aPresContext, mouseEvent, aStatus);
       sNormalLMouseEventInProcess = true;
       break;
@@ -1268,18 +1273,21 @@ EventStateManager::HandleCrossProcessEve
 // is a one-shot that will be cancelled when the user moves enough to fire
 // a drag.
 //
 void
 EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
                                         nsIFrame* inDownFrame,
                                         WidgetGUIEvent* inMouseDownEvent)
 {
-  if (!inMouseDownEvent->mFlags.mIsTrusted || IsRemoteTarget(mGestureDownContent))
+  if (!inMouseDownEvent->mFlags.mIsTrusted ||
+      IsRemoteTarget(mGestureDownContent) ||
+      sIsPointerLocked) {
     return;
+  }
 
   // just to be anal (er, safe)
   if (mClickHoldTimer) {
     mClickHoldTimer->Cancel();
     mClickHoldTimer = nullptr;
   }
 
   // if content clicked on has a popup, don't even start the timer
@@ -1351,17 +1359,17 @@ EventStateManager::sClickHoldCallback(ns
 // means that someone either ate the event or put up a context menu. This is our cue
 // to stop tracking the drag gesture. If we always did this, draggable items w/out
 // a context menu wouldn't be draggable after a certain length of time, which is
 // _not_ what we want.
 //
 void
 EventStateManager::FireContextClick()
 {
-  if (!mGestureDownContent || !mPresContext) {
+  if (!mGestureDownContent || !mPresContext || sIsPointerLocked) {
     return;
   }
 
 #ifdef XP_MACOSX
   // Hack to ensure that we don't show a context menu when the user
   // let go of the mouse after a long cpu-hogging operation prevented
   // us from handling any OS events. See bug 117589.
   if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kCGMouseButtonLeft))
--- a/dom/ipc/AppProcessChecker.cpp
+++ b/dom/ipc/AppProcessChecker.cpp
@@ -34,89 +34,125 @@ class PContentParent;
 
 class nsIPrincipal;
 #endif
 
 namespace mozilla {
 
 #ifdef MOZ_CHILD_PERMISSIONS
 
+static bool
+CheckAppTypeHelper(mozIApplication* aApp,
+                   AssertAppProcessType aType,
+                   const char* aCapability,
+                   bool aIsBrowserElement)
+{
+  bool aValid = false;
+
+  // isBrowser frames inherit their app descriptor to identify their
+  // data storage, but they don't inherit the capability associated
+  // with that descriptor.
+  if (aApp && (aType == ASSERT_APP_HAS_PERMISSION || !aIsBrowserElement)) {
+    switch (aType) {
+      case ASSERT_APP_HAS_PERMISSION:
+      case ASSERT_APP_PROCESS_PERMISSION:
+        if (!NS_SUCCEEDED(aApp->HasPermission(aCapability, &aValid))) {
+          aValid = false;
+        }
+        break;
+      case ASSERT_APP_PROCESS_MANIFEST_URL: {
+        nsAutoString manifestURL;
+        if (NS_SUCCEEDED(aApp->GetManifestURL(manifestURL)) &&
+            manifestURL.EqualsASCII(aCapability)) {
+          aValid = true;
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  return aValid;
+}
+
 bool
 AssertAppProcess(PBrowserParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
   if (!aActor) {
     NS_WARNING("Testing process capability for null actor");
     return false;
   }
 
   TabParent* tab = static_cast<TabParent*>(aActor);
   nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
-  bool aValid = false;
+
+  return CheckAppTypeHelper(app, aType, aCapability, tab->IsBrowserElement());
+}
 
-  // isBrowser frames inherit their app descriptor to identify their
-  // data storage, but they don't inherit the capability associated
-  // with that descriptor.
-  if (app && (aType == ASSERT_APP_HAS_PERMISSION || !tab->IsBrowserElement())) {
-    switch (aType) {
-      case ASSERT_APP_HAS_PERMISSION:
-      case ASSERT_APP_PROCESS_PERMISSION:
-        if (!NS_SUCCEEDED(app->HasPermission(aCapability, &aValid))) {
-          aValid = false;
-        }
-        break;
-      case ASSERT_APP_PROCESS_MANIFEST_URL: {
-        nsAutoString manifestURL;
-        if (NS_SUCCEEDED(app->GetManifestURL(manifestURL)) &&
-            manifestURL.EqualsASCII(aCapability)) {
-          aValid = true;
-        }
-        break;
-      }
-      default:
-        break;
+static bool
+CheckAppStatusHelper(mozIApplication* aApp,
+                     unsigned short aStatus)
+{
+  bool valid = false;
+
+  if (aApp) {
+    unsigned short appStatus = 0;
+    if (NS_SUCCEEDED(aApp->GetAppStatus(&appStatus))) {
+      valid = appStatus == aStatus;
     }
   }
-  return aValid;
+
+  return valid;
 }
 
 bool
 AssertAppStatus(PBrowserParent* aActor,
                 unsigned short aStatus)
 {
   if (!aActor) {
     NS_WARNING("Testing process capability for null actor");
     return false;
   }
 
   TabParent* tab = static_cast<TabParent*>(aActor);
   nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
 
-  bool valid = false;
+  return CheckAppStatusHelper(app, aStatus);
+}
+
+bool
+AssertAppProcess(TabContext& aContext,
+                 AssertAppProcessType aType,
+                 const char* aCapability)
+{
 
-  if (app) {
-    unsigned short appStatus = 0;
-    if (NS_SUCCEEDED(app->GetAppStatus(&appStatus))) {
-      valid = appStatus == aStatus;
-    }
-  }
+  nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
+  return CheckAppTypeHelper(app, aType, aCapability, aContext.IsBrowserElement());
+}
 
-  return valid;
+bool
+AssertAppStatus(TabContext& aContext,
+                unsigned short aStatus)
+{
+
+  nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
+  return CheckAppStatusHelper(app, aStatus);
 }
 
 bool
 AssertAppProcess(PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
-  const InfallibleTArray<PBrowserParent*>& browsers =
-    aActor->ManagedPBrowserParent();
-  for (uint32_t i = 0; i < browsers.Length(); ++i) {
-    if (AssertAppProcess(browsers[i], aType, aCapability)) {
+  nsTArray<TabContext> contextArray =
+    static_cast<ContentParent*>(aActor)->GetManagedTabContext();
+  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
+    if (AssertAppProcess(contextArray[i], aType, aCapability)) {
       return true;
     }
   }
 
   NS_ERROR(
     nsPrintfCString(
       "Security problem: Content process does not have `%s'.  It will be killed.\n",
       aCapability).get());
@@ -125,20 +161,20 @@ AssertAppProcess(PContentParent* aActor,
 
   return false;
 }
 
 bool
 AssertAppStatus(PContentParent* aActor,
                 unsigned short aStatus)
 {
-  const InfallibleTArray<PBrowserParent*>& browsers =
-    aActor->ManagedPBrowserParent();
-  for (uint32_t i = 0; i < browsers.Length(); ++i) {
-    if (AssertAppStatus(browsers[i], aStatus)) {
+  nsTArray<TabContext> contextArray =
+    static_cast<ContentParent*>(aActor)->GetManagedTabContext();
+  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
+    if (AssertAppStatus(contextArray[i], aStatus)) {
       return true;
     }
   }
 
   NS_ERROR(
     nsPrintfCString(
       "Security problem: Content process does not have `%d' status.  It will be killed.",
       aStatus).get());
@@ -165,24 +201,23 @@ AssertAppPrincipal(PContentParent* aActo
     static_cast<ContentParent*>(aActor)->KillHard();
     return false;
   }
 
   uint32_t principalAppId = aPrincipal->GetAppId();
   bool inBrowserElement = aPrincipal->GetIsInBrowserElement();
 
   // Check if the permission's appId matches a child we manage.
-  const InfallibleTArray<PBrowserParent*>& browsers =
-    aActor->ManagedPBrowserParent();
-  for (uint32_t i = 0; i < browsers.Length(); ++i) {
-    TabParent* tab = static_cast<TabParent*>(browsers[i]);
-    if (tab->OwnOrContainingAppId() == principalAppId) {
+  nsTArray<TabContext> contextArray =
+    static_cast<ContentParent*>(aActor)->GetManagedTabContext();
+  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
+    if (contextArray[i].OwnOrContainingAppId() == principalAppId) {
       // If the child only runs inBrowserElement content and the principal claims
       // it's not in a browser element, it's lying.
-      if (!tab->IsBrowserElement() || inBrowserElement) {
+      if (!contextArray[i].IsBrowserElement() || inBrowserElement) {
         return true;
       }
       break;
     }
   }
 
   NS_WARNING("Principal is invalid, killing app process");
   static_cast<ContentParent*>(aActor)->KillHard();
@@ -282,16 +317,31 @@ AssertAppProcess(mozilla::dom::PBrowserP
 
 bool
 AssertAppStatus(mozilla::dom::PBrowserParent* aActor,
                 unsigned short aStatus)
 {
   return true;
 }
 
+bool
+AssertAppProcess(const mozilla::dom::TabContext& aContext,
+                 AssertAppProcessType aType,
+                 const char* aCapability)
+{
+  return true;
+}
+
+bool
+AssertAppStatus(const mozilla::dom::TabContext& aContext,
+                unsigned short aStatus)
+{
+  return true;
+}
+
 
 bool
 AssertAppProcess(mozilla::dom::PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
   return true;
 }
--- a/dom/ipc/AppProcessChecker.h
+++ b/dom/ipc/AppProcessChecker.h
@@ -10,16 +10,17 @@
 
 #include <stdint.h>
 
 class nsIPrincipal;
 
 namespace mozilla {
 
 namespace dom {
+class TabContext;
 class PBrowserParent;
 class PContentParent;
 }
 
 namespace hal_sandbox {
 class PHalParent;
 }
 
@@ -43,16 +44,34 @@ AssertAppProcess(mozilla::dom::PBrowserP
  * Return true if the specified app has the specified status.
  * If this returns false, the browser will be killed.
  */
 bool
 AssertAppStatus(mozilla::dom::PBrowserParent* aActor,
                 unsigned short aStatus);
 
 /**
+ * Return true if the specified browser has the specified capability.
+ * If this returns false, the browser didn't have the capability and
+ * will be killed.
+ */
+bool
+AssertAppProcess(const mozilla::dom::TabContext& aContext,
+                 AssertAppProcessType aType,
+                 const char* aCapability);
+
+/**
+ * Return true if the specified app has the specified status.
+ * If this returns false, the browser will be killed.
+ */
+bool
+AssertAppStatus(const mozilla::dom::TabContext& aContext,
+                unsigned short aStatus);
+
+/**
  * Return true if any of the PBrowsers loaded in this content process
  * has the specified capability.  If this returns false, the process
  * didn't have the capability and will be killed.
  */
 bool
 AssertAppProcess(mozilla::dom::PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability);
--- a/dom/ipc/ContentBridgeChild.cpp
+++ b/dom/ipc/ContentBridgeChild.cpp
@@ -76,26 +76,28 @@ PBlobChild*
 ContentBridgeChild::SendPBlobConstructor(PBlobChild* actor,
                                          const BlobConstructorParams& params)
 {
   return PContentBridgeChild::SendPBlobConstructor(actor, params);
 }
 
 bool
 ContentBridgeChild::SendPBrowserConstructor(PBrowserChild* aActor,
+                                            const TabId& aTabId,
                                             const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const uint64_t& aID,
+                                            const ContentParentId& aCpID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser)
 {
   return PContentBridgeChild::SendPBrowserConstructor(aActor,
+                                                      aTabId,
                                                       aContext,
                                                       aChromeFlags,
-                                                      aID,
+                                                      aCpID,
                                                       aIsForApp,
                                                       aIsForBrowser);
 }
 
 // This implementation is identical to ContentChild::GetCPOWManager but we can't
 // move it to nsIContentChild because it calls ManagedPJavaScriptChild() which
 // only exists in PContentChild and PContentBridgeChild.
 jsipc::JavaScriptShared*
@@ -116,47 +118,51 @@ ContentBridgeChild::AllocPJavaScriptChil
 
 bool
 ContentBridgeChild::DeallocPJavaScriptChild(PJavaScriptChild *child)
 {
   return nsIContentChild::DeallocPJavaScriptChild(child);
 }
 
 PBrowserChild*
-ContentBridgeChild::AllocPBrowserChild(const IPCTabContext &aContext,
+ContentBridgeChild::AllocPBrowserChild(const TabId& aTabId,
+                                       const IPCTabContext &aContext,
                                        const uint32_t& aChromeFlags,
-                                       const uint64_t& aID,
+                                       const ContentParentId& aCpID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser)
 {
-  return nsIContentChild::AllocPBrowserChild(aContext,
+  return nsIContentChild::AllocPBrowserChild(aTabId,
+                                             aContext,
                                              aChromeFlags,
-                                             aID,
+                                             aCpID,
                                              aIsForApp,
                                              aIsForBrowser);
 }
 
 bool
 ContentBridgeChild::DeallocPBrowserChild(PBrowserChild* aChild)
 {
   return nsIContentChild::DeallocPBrowserChild(aChild);
 }
 
 bool
 ContentBridgeChild::RecvPBrowserConstructor(PBrowserChild* aActor,
+                                            const TabId& aTabId,
                                             const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const uint64_t& aID,
+                                            const ContentParentId& aCpID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser)
 {
   return ContentChild::GetSingleton()->RecvPBrowserConstructor(aActor,
+                                                               aTabId,
                                                                aContext,
                                                                aChromeFlags,
-                                                               aID,
+                                                               aCpID,
                                                                aIsForApp,
                                                                aIsForBrowser);
 }
 
 PBlobChild*
 ContentBridgeChild::AllocPBlobChild(const BlobConstructorParams& aParams)
 {
   return nsIContentChild::AllocPBlobChild(aParams);
--- a/dom/ipc/ContentBridgeChild.h
+++ b/dom/ipc/ContentBridgeChild.h
@@ -34,35 +34,38 @@ public:
 
   virtual PBlobChild*
   SendPBlobConstructor(PBlobChild* actor,
                        const BlobConstructorParams& params);
 
   jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
   virtual bool SendPBrowserConstructor(PBrowserChild* aActor,
+                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
-                                       const uint64_t& aID,
+                                       const ContentParentId& aCpID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser) MOZ_OVERRIDE;
 
 protected:
   virtual ~ContentBridgeChild();
 
-  virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+  virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
+                                            const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const uint64_t& aID,
+                                            const ContentParentId& aCpID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser) MOZ_OVERRIDE;
   virtual bool DeallocPBrowserChild(PBrowserChild*) MOZ_OVERRIDE;
   virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
+                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
-                                       const uint64_t& aID,
+                                       const ContentParentId& aCpID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser) MOZ_OVERRIDE;
 
   virtual mozilla::jsipc::PJavaScriptChild* AllocPJavaScriptChild() MOZ_OVERRIDE;
   virtual bool DeallocPJavaScriptChild(mozilla::jsipc::PJavaScriptChild*) MOZ_OVERRIDE;
 
   virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams) MOZ_OVERRIDE;
   virtual bool DeallocPBlobChild(PBlobChild*) MOZ_OVERRIDE;
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -82,26 +82,28 @@ PBlobParent*
 ContentBridgeParent::SendPBlobConstructor(PBlobParent* actor,
                                           const BlobConstructorParams& params)
 {
   return PContentBridgeParent::SendPBlobConstructor(actor, params);
 }
 
 PBrowserParent*
 ContentBridgeParent::SendPBrowserConstructor(PBrowserParent* aActor,
+                                             const TabId& aTabId,
                                              const IPCTabContext& aContext,
                                              const uint32_t& aChromeFlags,
-                                             const uint64_t& aID,
+                                             const ContentParentId& aCpID,
                                              const bool& aIsForApp,
                                              const bool& aIsForBrowser)
 {
   return PContentBridgeParent::SendPBrowserConstructor(aActor,
+                                                       aTabId,
                                                        aContext,
                                                        aChromeFlags,
-                                                       aID,
+                                                       aCpID,
                                                        aIsForApp,
                                                        aIsForBrowser);
 }
 
 PBlobParent*
 ContentBridgeParent::AllocPBlobParent(const BlobConstructorParams& aParams)
 {
   return nsIContentParent::AllocPBlobParent(aParams);
@@ -121,25 +123,27 @@ ContentBridgeParent::AllocPJavaScriptPar
 
 bool
 ContentBridgeParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
 {
   return nsIContentParent::DeallocPJavaScriptParent(parent);
 }
 
 PBrowserParent*
-ContentBridgeParent::AllocPBrowserParent(const IPCTabContext &aContext,
+ContentBridgeParent::AllocPBrowserParent(const TabId& aTabId,
+                                         const IPCTabContext &aContext,
                                          const uint32_t& aChromeFlags,
-                                         const uint64_t& aID,
+                                         const ContentParentId& aCpID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser)
 {
-  return nsIContentParent::AllocPBrowserParent(aContext,
+  return nsIContentParent::AllocPBrowserParent(aTabId,
+                                               aContext,
                                                aChromeFlags,
-                                               aID,
+                                               aCpID,
                                                aIsForApp,
                                                aIsForBrowser);
 }
 
 bool
 ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
 {
   return nsIContentParent::DeallocPBrowserParent(aParent);
--- a/dom/ipc/ContentBridgeParent.h
+++ b/dom/ipc/ContentBridgeParent.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ContentBridgeParent_h
 #define mozilla_dom_ContentBridgeParent_h
 
 #include "mozilla/dom/PContentBridgeParent.h"
 #include "mozilla/dom/nsIContentParent.h"
+#include "mozilla/dom/ipc/IdType.h"
 
 namespace mozilla {
 namespace dom {
 
 class ContentBridgeParent : public PContentBridgeParent
                           , public nsIContentParent
 {
 public:
@@ -28,41 +29,42 @@ public:
   Create(Transport* aTransport, ProcessId aOtherProcess);
 
   virtual PBlobParent*
   SendPBlobConstructor(PBlobParent* actor,
                        const BlobConstructorParams& params) MOZ_OVERRIDE;
 
   virtual PBrowserParent*
   SendPBrowserConstructor(PBrowserParent* aActor,
+                          const TabId& aTabId,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
-                          const uint64_t& aID,
+                          const ContentParentId& aCpID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) MOZ_OVERRIDE;
 
   jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
-  virtual uint64_t ChildID() MOZ_OVERRIDE
+  virtual ContentParentId ChildID() MOZ_OVERRIDE
   {
     return mChildID;
   }
   virtual bool IsForApp() MOZ_OVERRIDE
   {
     return mIsForApp;
   }
   virtual bool IsForBrowser() MOZ_OVERRIDE
   {
     return mIsForBrowser;
   }
 
 protected:
   virtual ~ContentBridgeParent();
 
-  void SetChildID(uint64_t aId)
+  void SetChildID(ContentParentId aId)
   {
     mChildID = aId;
   }
   void SetIsForApp(bool aIsForApp)
   {
     mIsForApp = aIsForApp;
   }
   void SetIsForBrowser(bool aIsForBrowser)
@@ -81,34 +83,35 @@ protected:
                                 const InfallibleTArray<jsipc::CpowEntry>& aCpows,
                                 const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
   virtual jsipc::PJavaScriptParent* AllocPJavaScriptParent() MOZ_OVERRIDE;
   virtual bool
   DeallocPJavaScriptParent(jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
 
   virtual PBrowserParent*
-  AllocPBrowserParent(const IPCTabContext &aContext,
+  AllocPBrowserParent(const TabId& aTabId,
+                      const IPCTabContext &aContext,
                       const uint32_t& aChromeFlags,
-                      const uint64_t& aID,
+                      const ContentParentId& aCpID,
                       const bool& aIsForApp,
                       const bool& aIsForBrowser) MOZ_OVERRIDE;
   virtual bool DeallocPBrowserParent(PBrowserParent*) MOZ_OVERRIDE;
 
   virtual PBlobParent*
   AllocPBlobParent(const BlobConstructorParams& aParams) MOZ_OVERRIDE;
 
   virtual bool DeallocPBlobParent(PBlobParent*) MOZ_OVERRIDE;
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentBridgeParent);
 
 protected: // members
   nsRefPtr<ContentBridgeParent> mSelfRef;
   Transport* mTransport; // owned
-  uint64_t mChildID;
+  ContentParentId mChildID;
   bool mIsForApp;
   bool mIsForBrowser;
 
 private:
   friend class ContentParent;
 };
 
 } // dom
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1113,50 +1113,55 @@ ContentChild::AllocPJavaScriptChild()
 
 bool
 ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *aChild)
 {
     return nsIContentChild::DeallocPJavaScriptChild(aChild);
 }
 
 PBrowserChild*
-ContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
+ContentChild::AllocPBrowserChild(const TabId& aTabId,
+                                 const IPCTabContext& aContext,
                                  const uint32_t& aChromeFlags,
-                                 const uint64_t& aID,
+                                 const ContentParentId& aCpID,
                                  const bool& aIsForApp,
                                  const bool& aIsForBrowser)
 {
-    return nsIContentChild::AllocPBrowserChild(aContext,
+    return nsIContentChild::AllocPBrowserChild(aTabId,
+                                               aContext,
                                                aChromeFlags,
-                                               aID,
+                                               aCpID,
                                                aIsForApp,
                                                aIsForBrowser);
 }
 
 bool
 ContentChild::SendPBrowserConstructor(PBrowserChild* aActor,
+                                      const TabId& aTabId,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
-                                      const uint64_t& aID,
+                                      const ContentParentId& aCpID,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
     return PContentChild::SendPBrowserConstructor(aActor,
+                                                  aTabId,
                                                   aContext,
                                                   aChromeFlags,
-                                                  aID,
+                                                  aCpID,
                                                   aIsForApp,
                                                   aIsForBrowser);
 }
 
 bool
 ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
+                                      const TabId& aTabId,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
-                                      const uint64_t& aID,
+                                      const ContentParentId& aCpID,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
     // This runs after AllocPBrowserChild() returns and the IPC machinery for this
     // PBrowserChild has been set up.
 
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     if (os) {
@@ -1170,17 +1175,17 @@ ContentChild::RecvPBrowserConstructor(PB
         hasRunOnce = true;
 
         MOZ_ASSERT(!sFirstIdleTask);
         sFirstIdleTask = NewRunnableFunction(FirstIdle);
         MessageLoop::current()->PostIdleTask(FROM_HERE, sFirstIdleTask);
 
         // Redo InitProcessAttributes() when the app or browser is really
         // launching so the attributes will be correct.
-        mID = aID;
+        mID = aCpID;
         mIsForApp = aIsForApp;
         mIsForBrowser = aIsForBrowser;
         InitProcessAttributes();
     }
 
     return true;
 }
 
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -130,19 +130,20 @@ public:
 #endif
 
     virtual bool RecvSetProcessSandbox() MOZ_OVERRIDE;
 
     PBackgroundChild*
     AllocPBackgroundChild(Transport* aTransport, ProcessId aOtherProcess)
                           MOZ_OVERRIDE;
 
-    virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+    virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
+                                              const IPCTabContext& aContext,
                                               const uint32_t& aChromeFlags,
-                                              const uint64_t& aID,
+                                              const ContentParentId& aCpID,
                                               const bool& aIsForApp,
                                               const bool& aIsForBrowser);
     virtual bool DeallocPBrowserChild(PBrowserChild*);
 
     virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequestChild(const DeviceStorageParams&);
     virtual bool DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*);
 
     virtual PFileSystemRequestChild* AllocPFileSystemRequestChild(const FileSystemParams&);
@@ -356,42 +357,44 @@ public:
 #ifdef ANDROID
     gfxIntSize GetScreenSize() { return mScreenSize; }
 #endif
 
     // Get the directory for IndexedDB files. We query the parent for this and
     // cache the value
     nsString &GetIndexedDBPath();
 
-    uint64_t GetID() { return mID; }
+    ContentParentId GetID() { return mID; }
 
     bool IsForApp() { return mIsForApp; }
     bool IsForBrowser() { return mIsForBrowser; }
 
     virtual PBlobChild*
     SendPBlobConstructor(PBlobChild* actor,
                          const BlobConstructorParams& params) MOZ_OVERRIDE;
 
     virtual PFileDescriptorSetChild*
     AllocPFileDescriptorSetChild(const FileDescriptor&) MOZ_OVERRIDE;
 
     virtual bool
     DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*) MOZ_OVERRIDE;
 
     virtual bool SendPBrowserConstructor(PBrowserChild* actor,
+                                         const TabId& aTabId,
                                          const IPCTabContext& context,
                                          const uint32_t& chromeFlags,
-                                         const uint64_t& aID,
+                                         const ContentParentId& aCpID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
 
     virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
+                                         const TabId& aTabId,
                                          const IPCTabContext& aContext,
                                          const uint32_t& aChromeFlags,
-                                         const uint64_t& aID,
+                                         const ContentParentId& aCpID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
     virtual PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) MOZ_OVERRIDE;
     virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) MOZ_OVERRIDE;
 
     void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
 
 private:
@@ -414,17 +417,17 @@ private:
 
     /**
      * An ID unique to the process containing our corresponding
      * content parent.
      *
      * We expect our content parent to set this ID immediately after opening a
      * channel to us.
      */
-    uint64_t mID;
+    ContentParentId mID;
 
     AppInfo mAppInfo;
 
 #ifdef ANDROID
     gfxIntSize mScreenSize;
 #endif
 
     bool mIsForApp;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -128,16 +128,17 @@
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "gfxPrefs.h"
 #include "prio.h"
 #include "private/pprio.h"
+#include "ContentProcessManager.h"
 
 #if defined(ANDROID) || defined(LINUX)
 #include "nsSystemInfo.h"
 #endif
 
 #if defined(XP_LINUX)
 #include "mozilla/Hal.h"
 #endif
@@ -843,27 +844,24 @@ ContentParent::PreallocatedProcessReady(
 {
 #ifdef MOZ_NUWA_PROCESS
     return PreallocatedProcessManager::PreallocatedProcessReady();
 #else
     return true;
 #endif
 }
 
-typedef std::map<ContentParent*, std::set<ContentParent*> > GrandchildMap;
-static GrandchildMap sGrandchildProcessMap;
-
-std::map<uint64_t, ContentParent*> sContentParentMap;
-
 bool
 ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext,
                                       const hal::ProcessPriority& aPriority,
-                                      uint64_t* aId,
+                                      const TabId& aOpenerTabId,
+                                      ContentParentId* aCpId,
                                       bool* aIsForApp,
-                                      bool* aIsForBrowser)
+                                      bool* aIsForBrowser,
+                                      TabId* aTabId)
 {
 #if 0
     if (!CanOpenBrowser(aContext)) {
         return false;
     }
 #endif
     nsRefPtr<ContentParent> cp;
     MaybeInvalidTabContext tc(aContext);
@@ -882,50 +880,77 @@ ContentParent::RecvCreateChildProcess(co
     }
     else {
         cp = GetNewOrUsedBrowserProcess(/* isBrowserElement = */ true,
                                         aPriority,
                                         this);
     }
 
     if (!cp) {
-        *aId = 0;
+        *aCpId = 0;
         *aIsForApp = false;
         *aIsForBrowser = false;
         return true;
     }
 
-    *aId = cp->ChildID();
+    *aCpId = cp->ChildID();
     *aIsForApp = cp->IsForApp();
     *aIsForBrowser = cp->IsForBrowser();
-    sContentParentMap[*aId] = cp;
-    auto iter = sGrandchildProcessMap.find(this);
-    if (iter == sGrandchildProcessMap.end()) {
-        std::set<ContentParent*> children;
-        children.insert(cp);
-        sGrandchildProcessMap[this] = children;
-    } else {
-        iter->second.insert(cp);
+
+    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+    cpm->AddContentProcess(cp, this->ChildID());
+
+    if (cpm->AddGrandchildProcess(this->ChildID(), cp->ChildID())) {
+        // Pre-allocate a TabId here to save one time IPC call at app startup.
+        *aTabId = AllocateTabId(aOpenerTabId,
+                                aContext,
+                                cp->ChildID());
+        return (*aTabId != 0);
     }
-    return true;
+
+    return false;
 }
 
 bool
-ContentParent::AnswerBridgeToChildProcess(const uint64_t& id)
+ContentParent::AnswerBridgeToChildProcess(const ContentParentId& aCpId)
 {
-    ContentParent* cp = sContentParentMap[id];
-    auto iter = sGrandchildProcessMap.find(this);
-    if (iter != sGrandchildProcessMap.end() &&
-        iter->second.find(cp) != iter->second.end()) {
-        return PContentBridge::Bridge(this, cp);
-    } else {
-        // You can't bridge to a process you didn't open!
-        KillHard();
-        return false;
+    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+    ContentParent* cp = cpm->GetContentProcessById(aCpId);
+
+    if (cp) {
+        ContentParentId parentId;
+        if (cpm->GetParentProcessId(cp->ChildID(), &parentId) &&
+            parentId == this->ChildID()) {
+            return PContentBridge::Bridge(this, cp);
+        }
     }
+
+    // You can't bridge to a process you didn't open!
+    KillHard();
+    return false;
+}
+
+static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement)
+{
+    // Propagate the private-browsing status of the element's parent
+    // docshell to the remote docshell, via the chrome flags.
+    nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
+    MOZ_ASSERT(frameElement);
+    nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow();
+    if (!win) {
+        NS_WARNING("Remote frame has no window");
+        return nullptr;
+    }
+    nsIDocShell* docShell = win->GetDocShell();
+    if (!docShell) {
+        NS_WARNING("Remote frame has no docshell");
+        return nullptr;
+    }
+
+    return docShell;
 }
 
 bool
 ContentParent::AnswerLoadPlugin(const uint32_t& aPluginId)
 {
     return mozilla::plugins::SetupBridge(aPluginId, this);
 }
 
@@ -943,67 +968,69 @@ ContentParent::CreateBrowserOrApp(const 
                                   ContentParent* aOpenerContentParent)
 {
     if (!sCanLaunchSubprocesses) {
         return nullptr;
     }
 
     ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
     bool isInContentProcess = (XRE_GetProcessType() != GeckoProcessType_Default);
+    TabId tabId;
+
+    nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
+    TabId openerTabId;
+    if (docShell) {
+        openerTabId = TabParent::GetTabIdFrom(docShell);
+    }
 
     if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
         nsRefPtr<TabParent> tp;
         nsRefPtr<nsIContentParent> constructorSender;
         if (isInContentProcess) {
             MOZ_ASSERT(aContext.IsBrowserElement());
-            constructorSender =
-                CreateContentBridgeParent(aContext, initialPriority);
+            constructorSender = CreateContentBridgeParent(aContext,
+                                                          initialPriority,
+                                                          openerTabId,
+                                                          &tabId);
         } else {
-          if (aOpenerContentParent) {
-            constructorSender = aOpenerContentParent;
-          } else {
-            constructorSender =
-                GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(),
-                                           initialPriority);
-          }
+            if (aOpenerContentParent) {
+                constructorSender = aOpenerContentParent;
+            } else {
+                constructorSender =
+                    GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(),
+                                               initialPriority);
+            }
+            tabId = AllocateTabId(openerTabId,
+                                  aContext.AsIPCTabContext(),
+                                  constructorSender->ChildID());
         }
         if (constructorSender) {
             uint32_t chromeFlags = 0;
 
-            // Propagate the private-browsing status of the element's parent
-            // docshell to the remote docshell, via the chrome flags.
-            nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
-            MOZ_ASSERT(frameElement);
-            nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow();
-            if (!win) {
-                NS_WARNING("Remote frame has no window");
-                return nullptr;
-            }
-            nsIDocShell* docShell = win->GetDocShell();
-            if (!docShell) {
-                NS_WARNING("Remote frame has no docshell");
-                return nullptr;
-            }
             nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
             if (loadContext && loadContext->UsePrivateBrowsing()) {
                 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
             }
             bool affectLifetime;
             docShell->GetAffectPrivateSessionLifetime(&affectLifetime);
             if (affectLifetime) {
                 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
             }
 
-            nsRefPtr<TabParent> tp(new TabParent(constructorSender,
+            if (tabId == 0) {
+                return nullptr;
+            }
+            nsRefPtr<TabParent> tp(new TabParent(constructorSender, tabId,
                                                  aContext, chromeFlags));
             tp->SetOwnerElement(aFrameElement);
 
             PBrowserParent* browser = constructorSender->SendPBrowserConstructor(
                 // DeallocPBrowserParent() releases this ref.
                 tp.forget().take(),
+                tabId,
                 aContext.AsIPCTabContext(),
                 chromeFlags,
                 constructorSender->ChildID(),
                 constructorSender->IsForApp(),
                 constructorSender->IsForBrowser());
             return static_cast<TabParent*>(browser);
         }
         return nullptr;
@@ -1013,17 +1040,20 @@ ContentParent::CreateBrowserOrApp(const 
     // shouldn't be null, because we otherwise would have gone into the
     // !HasOwnApp() branch above.
     nsRefPtr<nsIContentParent> parent;
     bool reused = false;
     bool tookPreallocated = false;
     nsAutoString manifestURL;
 
     if (isInContentProcess) {
-      parent = CreateContentBridgeParent(aContext, initialPriority);
+      parent = CreateContentBridgeParent(aContext,
+                                         initialPriority,
+                                         openerTabId,
+                                         &tabId);
     }
     else {
         nsCOMPtr<mozIApplication> ownApp = aContext.GetOwnApp();
 
         if (!sAppContentParents) {
             sAppContentParents =
                 new nsDataHashtable<nsStringHashKey, ContentParent*>();
         }
@@ -1083,30 +1113,34 @@ ContentParent::CreateBrowserOrApp(const 
         if (!p) {
             p = GetNewOrPreallocatedAppProcess(ownApp,
                                                initialPriority,
                                                nullptr,
                                                &tookPreallocated);
             MOZ_ASSERT(p);
             sAppContentParents->Put(manifestURL, p);
         }
+        tabId = AllocateTabId(openerTabId,
+                              aContext.AsIPCTabContext(),
+                              p->ChildID());
         parent = static_cast<nsIContentParent*>(p);
     }
 
-    if (!parent) {
+    if (!parent || (tabId == 0)) {
         return nullptr;
     }
 
     uint32_t chromeFlags = 0;
 
-    nsRefPtr<TabParent> tp = new TabParent(parent, aContext, chromeFlags);
+    nsRefPtr<TabParent> tp = new TabParent(parent, tabId, aContext, chromeFlags);
     tp->SetOwnerElement(aFrameElement);
     PBrowserParent* browser = parent->SendPBrowserConstructor(
         // DeallocPBrowserParent() releases this ref.
         nsRefPtr<TabParent>(tp).forget().take(),
+        tabId,
         aContext.AsIPCTabContext(),
         chromeFlags,
         parent->ChildID(),
         parent->IsForApp(),
         parent->IsForBrowser());
 
     if (isInContentProcess) {
         // Just return directly without the following check in content process.
@@ -1139,37 +1173,43 @@ ContentParent::CreateBrowserOrApp(const 
 
     parent->AsContentParent()->MaybeTakeCPUWakeLock(aFrameElement);
 
     return static_cast<TabParent*>(browser);
 }
 
 /*static*/ ContentBridgeParent*
 ContentParent::CreateContentBridgeParent(const TabContext& aContext,
-                                         const hal::ProcessPriority& aPriority)
+                                         const hal::ProcessPriority& aPriority,
+                                         const TabId& aOpenerTabId,
+                                         /*out*/ TabId* aTabId)
 {
+    MOZ_ASSERT(aTabId);
+
     ContentChild* child = ContentChild::GetSingleton();
-    uint64_t id;
+    ContentParentId cpId;
     bool isForApp;
     bool isForBrowser;
     if (!child->SendCreateChildProcess(aContext.AsIPCTabContext(),
                                        aPriority,
-                                       &id,
+                                       aOpenerTabId,
+                                       &cpId,
                                        &isForApp,
-                                       &isForBrowser)) {
+                                       &isForBrowser,
+                                       aTabId)) {
         return nullptr;
     }
-    if (id == 0) {
+    if (cpId == 0) {
         return nullptr;
     }
-    if (!child->CallBridgeToChildProcess(id)) {
+    if (!child->CallBridgeToChildProcess(cpId)) {
         return nullptr;
     }
     ContentBridgeParent* parent = child->GetLastBridge();
-    parent->SetChildID(id);
+    parent->SetChildID(cpId);
     parent->SetIsForApp(isForApp);
     parent->SetIsForBrowser(isForBrowser);
     return parent;
 }
 
 void
 ContentParent::GetAll(nsTArray<ContentParent*>& aArray)
 {
@@ -1495,23 +1535,16 @@ ContentParent::MarkAsDead()
         sPrivateContent->RemoveElement(this);
         if (!sPrivateContent->Length()) {
             delete sPrivateContent;
             sPrivateContent = nullptr;
         }
     }
 
     mIsAlive = false;
-
-    sGrandchildProcessMap.erase(this);
-    for (auto iter = sGrandchildProcessMap.begin();
-         iter != sGrandchildProcessMap.end();
-         iter++) {
-        iter->second.erase(this);
-    }
 }
 
 void
 ContentParent::OnChannelError()
 {
     nsRefPtr<ContentParent> content(this);
 #ifdef MOZ_NUWA_PROCESS
     // Handle app or Nuwa process exit before normal channel error handling.
@@ -1739,27 +1772,27 @@ ContentParent::ActorDestroy(ActorDestroy
     // |this|.  If so, when we go out of scope here, we're deleted and
     // all hell breaks loose.
     //
     // This runnable ensures that a reference to |this| lives on at
     // least until after the current task finishes running.
     NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
 
     // Destroy any processes created by this ContentParent
-    auto iter = sGrandchildProcessMap.find(this);
-    if (iter != sGrandchildProcessMap.end()) {
-        for(auto child = iter->second.begin();
-            child != iter->second.end();
-            child++) {
-            MessageLoop::current()->PostTask(
-                FROM_HERE,
-                NewRunnableMethod(*child, &ContentParent::ShutDownProcess,
-                                  /* closeWithError */ false));
-        }
+    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+    nsTArray<ContentParentId> childIDArray =
+        cpm->GetAllChildProcessById(this->ChildID());
+    for(uint32_t i = 0; i < childIDArray.Length(); i++) {
+        ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]);
+        MessageLoop::current()->PostTask(
+            FROM_HERE,
+            NewRunnableMethod(cp, &ContentParent::ShutDownProcess,
+                              /* closeWithError */ false));
     }
+    cpm->RemoveContentProcess(this->ChildID());
 }
 
 void
 ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
 {
     // There can be more than one PBrowser for a given app process
     // because of popup windows.  PBrowsers can also destroy
     // concurrently.  When all the PBrowsers are destroying, kick off
@@ -1912,16 +1945,18 @@ ContentParent::ContentParent(mozIApplica
     }
     mSubprocess->LaunchAndWaitForProcessHandle(extraArgs);
 
     Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle());
 
     InitInternal(aInitialPriority,
                  true, /* Setup off-main thread compositing */
                  true  /* Send registered chrome */);
+
+    ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 
 #ifdef MOZ_NUWA_PROCESS
 static const mozilla::ipc::FileDescriptor*
 FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
                         ProtocolId aProtoId)
 {
     for (unsigned int i = 0; i < aFds.Length(); i++) {
@@ -1989,16 +2024,18 @@ ContentParent::ContentParent(ContentPare
         priority = PROCESS_PRIORITY_PREALLOC;
     } else {
         priority = PROCESS_PRIORITY_FOREGROUND;
     }
 
     InitInternal(priority,
                  false, /* Setup Off-main thread compositing */
                  false  /* Send registered chrome */);
+
+    ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 #endif  // MOZ_NUWA_PROCESS
 
 ContentParent::~ContentParent()
 {
     if (mForceKillTask) {
         mForceKillTask->Cancel();
     }
@@ -2799,20 +2836,20 @@ ContentParent::AllocPBackgroundParent(Tr
 PSharedBufferManagerParent*
 ContentParent::AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTransport,
                                                 base::ProcessId aOtherProcess)
 {
     return SharedBufferManagerParent::Create(aTransport, aOtherProcess);
 }
 
 bool
-ContentParent::RecvGetProcessAttributes(uint64_t* aId,
+ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
                                         bool* aIsForApp, bool* aIsForBrowser)
 {
-    *aId = mChildID;
+    *aCpId = mChildID;
     *aIsForApp = IsForApp();
     *aIsForBrowser = mIsForBrowser;
 
     return true;
 }
 
 bool
 ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
@@ -2850,25 +2887,27 @@ ContentParent::AllocPJavaScriptParent()
 
 bool
 ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
 {
     return nsIContentParent::DeallocPJavaScriptParent(parent);
 }
 
 PBrowserParent*
-ContentParent::AllocPBrowserParent(const IPCTabContext& aContext,
+ContentParent::AllocPBrowserParent(const TabId& aTabId,
+                                   const IPCTabContext& aContext,
                                    const uint32_t& aChromeFlags,
-                                   const uint64_t& aId,
+                                   const ContentParentId& aCpId,
                                    const bool& aIsForApp,
                                    const bool& aIsForBrowser)
 {
-    return nsIContentParent::AllocPBrowserParent(aContext,
+    return nsIContentParent::AllocPBrowserParent(aTabId,
+                                                 aContext,
                                                  aChromeFlags,
-                                                 aId,
+                                                 aCpId,
                                                  aIsForApp,
                                                  aIsForBrowser);
 }
 
 bool
 ContentParent::DeallocPBrowserParent(PBrowserParent* frame)
 {
     return nsIContentParent::DeallocPBrowserParent(frame);
@@ -3859,26 +3898,28 @@ bool
 ContentParent::RecvSystemMessageHandled()
 {
     SystemMessageHandledListener::OnSystemMessageHandled();
     return true;
 }
 
 PBrowserParent*
 ContentParent::SendPBrowserConstructor(PBrowserParent* aActor,
+                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
-                                       const uint64_t& aId,
+                                       const ContentParentId& aCpId,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser)
 {
     return PContentParent::SendPBrowserConstructor(aActor,
+                                                   aTabId,
                                                    aContext,
                                                    aChromeFlags,
-                                                   aId,
+                                                   aCpId,
                                                    aIsForApp,
                                                    aIsForBrowser);
 }
 
 bool
 ContentParent::RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint)
 {
 #ifdef MOZ_WIDGET_GONK
@@ -4167,16 +4208,76 @@ ContentParent::NotifyUpdatedDictionaries
     InfallibleTArray<nsString> dictionaries;
     spellChecker->GetDictionaryList(&dictionaries);
 
     for (size_t i = 0; i < processes.Length(); ++i) {
         unused << processes[i]->SendUpdateDictionaryList(dictionaries);
     }
 }
 
+/*static*/ TabId
+ContentParent::AllocateTabId(const TabId& aOpenerTabId,
+                             const IPCTabContext& aContext,
+                             const ContentParentId& aCpId)
+{
+    TabId tabId;
+    if (XRE_GetProcessType() == GeckoProcessType_Default) {
+        ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
+        tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId);
+    }
+    else {
+        ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId,
+                                                        aContext,
+                                                        aCpId,
+                                                        &tabId);
+    }
+    return tabId;
+}
+
+/*static*/ void
+ContentParent::DeallocateTabId(const TabId& aTabId,
+                               const ContentParentId& aCpId)
+{
+    if (XRE_GetProcessType() == GeckoProcessType_Default) {
+        ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId,
+                                                               aTabId);
+    }
+    else {
+        ContentChild::GetSingleton()->SendDeallocateTabId(aTabId);
+    }
+}
+
+bool
+ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId,
+                                 const IPCTabContext& aContext,
+                                 const ContentParentId& aCpId,
+                                 TabId* aTabId)
+{
+    *aTabId = AllocateTabId(aOpenerTabId, aContext, aCpId);
+    if (!(*aTabId)) {
+        return false;
+    }
+    return true;
+}
+
+bool
+ContentParent::RecvDeallocateTabId(const TabId& aTabId)
+{
+    DeallocateTabId(aTabId, this->ChildID());
+    return true;
+}
+
+nsTArray<TabContext>
+ContentParent::GetManagedTabContext()
+{
+    return Move(ContentProcessManager::GetSingleton()->
+        GetTabContextByContentProcess(this->ChildID()));
+}
+
+
 } // namespace dom
 } // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
 NS_IMETHODIMP
 ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) {
     mozilla::unused << mParent->SendNotifyIdleObserver(mObserver,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -138,20 +138,22 @@ public:
     static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray);
 
     static bool IgnoreIPCPrincipal();
 
     static void NotifyUpdatedDictionaries();
 
     virtual bool RecvCreateChildProcess(const IPCTabContext& aContext,
                                         const hal::ProcessPriority& aPriority,
-                                        uint64_t* aId,
+                                        const TabId& aOpenerTabId,
+                                        ContentParentId* aCpId,
                                         bool* aIsForApp,
-                                        bool* aIsForBrowser) MOZ_OVERRIDE;
-    virtual bool AnswerBridgeToChildProcess(const uint64_t& id) MOZ_OVERRIDE;
+                                        bool* aIsForBrowser,
+                                        TabId* aTabId) MOZ_OVERRIDE;
+    virtual bool AnswerBridgeToChildProcess(const ContentParentId& aCpId) MOZ_OVERRIDE;
 
     virtual bool AnswerLoadPlugin(const uint32_t& aPluginId) MOZ_OVERRIDE;
     virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
                                  nsTArray<PluginTag>* aPlugins,
                                  uint32_t* aNewPluginEpoch) MOZ_OVERRIDE;
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
 
@@ -179,16 +181,23 @@ public:
     void NotifyTabDestroyed(PBrowserParent* aTab,
                             bool aNotifiedDestroying);
 
     TestShellParent* CreateTestShell();
     bool DestroyTestShell(TestShellParent* aTestShell);
     TestShellParent* GetTestShellSingleton();
     jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
+    static TabId
+    AllocateTabId(const TabId& aOpenerTabId,
+                  const IPCTabContext& aContext,
+                  const ContentParentId& aCpId);
+    static void
+    DeallocateTabId(const TabId& aTabId, const ContentParentId& aCpId);
+
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
     virtual bool IsForApp() MOZ_OVERRIDE;
     virtual bool IsForBrowser() MOZ_OVERRIDE
     {
       return mIsForBrowser;
@@ -217,17 +226,17 @@ public:
 
     /**
      * Kill our subprocess and make sure it dies.  Should only be used
      * in emergency situations since it bypasses the normal shutdown
      * process.
      */
     void KillHard();
 
-    uint64_t ChildID() MOZ_OVERRIDE { return mChildID; }
+    ContentParentId ChildID() MOZ_OVERRIDE { return mChildID; }
     const nsString& AppManifestURL() const { return mAppManifestURL; }
 
     bool IsPreallocated();
 
     /**
      * Get a user-friendly name for this ContentParent.  We make no guarantees
      * about this name: It might not be unique, apps can spoof special names,
      * etc.  So please don't use this name to make any decisions about the
@@ -286,16 +295,24 @@ public:
     bool CycleCollectWithLogs(bool aDumpAllTraces,
                               nsICycleCollectorLogSink* aSink,
                               nsIDumpGCAndCCLogsCallback* aCallback);
 
     virtual PBlobParent* SendPBlobConstructor(
         PBlobParent* aActor,
         const BlobConstructorParams& aParams) MOZ_OVERRIDE;
 
+    virtual bool RecvAllocateTabId(const TabId& aOpenerTabId,
+                                   const IPCTabContext& aContext,
+                                   const ContentParentId& aCpId,
+                                   TabId* aTabId) MOZ_OVERRIDE;
+
+    virtual bool RecvDeallocateTabId(const TabId& aTabId) MOZ_OVERRIDE;
+
+    nsTArray<TabContext> GetManagedTabContext();
 protected:
     void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
     void OnNuwaForkTimeout();
 
     bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
 
 private:
@@ -314,25 +331,28 @@ private:
     GetNewOrPreallocatedAppProcess(mozIApplication* aApp,
                                    hal::ProcessPriority aInitialPriority,
                                    ContentParent* aOpener,
                                    /*out*/ bool* aTookPreAllocated = nullptr);
 
     static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement);
 
     static ContentBridgeParent* CreateContentBridgeParent(const TabContext& aContext,
-                                                          const hal::ProcessPriority& aPriority);
+                                                          const hal::ProcessPriority& aPriority,
+                                                          const TabId& aOpenerTabId,
+                                                          /*out*/ TabId* aTabId);
 
     // Hide the raw constructor methods since we don't want client code
     // using them.
     virtual PBrowserParent* SendPBrowserConstructor(
         PBrowserParent* actor,
+        const TabId& aTabId,
         const IPCTabContext& context,
         const uint32_t& chromeFlags,
-        const uint64_t& aId,
+        const ContentParentId& aCpId,
         const bool& aIsForApp,
         const bool& aIsForBrowser) MOZ_OVERRIDE;
     using PContentParent::SendPTestShellConstructor;
 
     // No more than one of !!aApp, aIsForBrowser, and aIsForPreallocated may be
     // true.
     ContentParent(mozIApplication* aApp,
                   ContentParent* aOpener,
@@ -413,30 +433,31 @@ private:
 
     PSharedBufferManagerParent*
     AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTranport,
                                      base::ProcessId aOtherProcess) MOZ_OVERRIDE;
     PBackgroundParent*
     AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess)
                            MOZ_OVERRIDE;
 
-    virtual bool RecvGetProcessAttributes(uint64_t* aId,
+    virtual bool RecvGetProcessAttributes(ContentParentId* aCpId,
                                           bool* aIsForApp,
                                           bool* aIsForBrowser) MOZ_OVERRIDE;
     virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
                                                InfallibleTArray<nsString>* dictionaries,
                                                ClipboardCapabilities* clipboardCaps)
         MOZ_OVERRIDE;
 
     virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
 
     virtual bool DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*) MOZ_OVERRIDE;
-    virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext,
+    virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
+                                                const IPCTabContext& aContext,
                                                 const uint32_t& aChromeFlags,
-                                                const uint64_t& aId,
+                                                const ContentParentId& aCpId,
                                                 const bool& aIsForApp,
                                                 const bool& aIsForBrowser) MOZ_OVERRIDE;
     virtual bool DeallocPBrowserParent(PBrowserParent* frame) MOZ_OVERRIDE;
 
     virtual PDeviceStorageRequestParent*
     AllocPDeviceStorageRequestParent(const DeviceStorageParams&) MOZ_OVERRIDE;
     virtual bool DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent*) MOZ_OVERRIDE;
 
@@ -696,17 +717,17 @@ private:
 
     // If you add strong pointers to cycle collected objects here, be sure to
     // release these objects in ShutDownProcess.  See the comment there for more
     // details.
 
     GeckoChildProcessHost* mSubprocess;
     ContentParent* mOpener;
 
-    uint64_t mChildID;
+    ContentParentId mChildID;
     int32_t mGeolocationWatchID;
 
     nsString mAppManifestURL;
 
     /**
      * We cache mAppName instead of looking it up using mAppManifestURL when we
      * need it because it turns out that getting an app from the apps service is
      * expensive.
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessManager.cpp
@@ -0,0 +1,276 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* 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 "ContentProcessManager.h"
+#include "ContentParent.h"
+
+#include "mozilla/StaticPtr.h"
+#include "mozilla/ClearOnShutdown.h"
+
+#include "nsPrintfCString.h"
+
+// XXX need another bug to move this to a common header.
+#ifdef DISABLE_ASSERTS_FOR_FUZZING
+#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
+#else
+#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
+#endif
+
+namespace mozilla {
+namespace dom {
+
+static uint64_t gTabId = 0;
+
+/* static */
+StaticAutoPtr<ContentProcessManager>
+ContentProcessManager::sSingleton;
+
+/* static */ ContentProcessManager*
+ContentProcessManager::GetSingleton()
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+
+  if (!sSingleton) {
+    sSingleton = new ContentProcessManager();
+    ClearOnShutdown(&sSingleton);
+  }
+  return sSingleton;
+}
+
+void
+ContentProcessManager::AddContentProcess(ContentParent* aChildCp,
+                                         const ContentParentId& aParentCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aChildCp);
+
+  ContentProcessInfo info;
+  info.mCp = aChildCp;
+  info.mParentCpId = aParentCpId;
+  mContentParentMap[aChildCp->ChildID()] = info;
+}
+
+void
+ContentProcessManager::RemoveContentProcess(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mContentParentMap.find(aChildCpId) != mContentParentMap.end());
+
+  mContentParentMap.erase(aChildCpId);
+  for (auto iter = mContentParentMap.begin();
+       iter != mContentParentMap.end();
+       ++iter) {
+    if (!iter->second.mChildrenCpId.empty()) {
+      iter->second.mChildrenCpId.erase(aChildCpId);
+    }
+  }
+}
+
+bool
+ContentProcessManager::AddGrandchildProcess(const ContentParentId& aParentCpId,
+                                            const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aParentCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING("Parent process should be already in map!");
+    return false;
+  }
+  iter->second.mChildrenCpId.insert(aChildCpId);
+  return true;
+}
+
+bool
+ContentProcessManager::GetParentProcessId(const ContentParentId& aChildCpId,
+                                          /*out*/ ContentParentId* aParentCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return false;
+  }
+  *aParentCpId = iter->second.mParentCpId;
+  return true;
+}
+
+ContentParent*
+ContentProcessManager::GetContentProcessById(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return nullptr;
+  }
+  return iter->second.mCp;
+}
+
+nsTArray<ContentParentId>
+ContentProcessManager::GetAllChildProcessById(const ContentParentId& aParentCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<ContentParentId> cpIdArray;
+  auto iter = mContentParentMap.find(aParentCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return Move(cpIdArray);
+  }
+
+  for (auto cpIter = iter->second.mChildrenCpId.begin();
+       cpIter != iter->second.mChildrenCpId.end();
+       ++cpIter) {
+    cpIdArray.AppendElement(*cpIter);
+  }
+
+  return Move(cpIdArray);
+}
+
+TabId
+ContentProcessManager::AllocateTabId(const TabId& aOpenerTabId,
+                                     const IPCTabContext& aContext,
+                                     const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return TabId(0);
+  }
+
+  struct RemoteFrameInfo info;
+
+  const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
+  // If it's a PopupIPCTabContext, it's the case that a TabChild want to
+  // open a new tab. aOpenerTabId has to be it's parent frame's opener id.
+  if (appBrowser.type() == IPCTabAppBrowserContext::TPopupIPCTabContext) {
+    auto remoteFrameIter = iter->second.mRemoteFrames.find(aOpenerTabId);
+    if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
+      ASSERT_UNLESS_FUZZING("Failed to find parent frame's opener id.");
+      return TabId(0);
+    }
+
+    info.mOpenerTabId = remoteFrameIter->second.mOpenerTabId;
+
+    const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext();
+    MOZ_ASSERT(ipcContext.opener().type() == PBrowserOrId::TTabId);
+
+    remoteFrameIter = iter->second.mRemoteFrames.find(ipcContext.opener().get_TabId());
+    if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
+      ASSERT_UNLESS_FUZZING("Failed to find tab id.");
+      return TabId(0);
+    }
+
+    info.mContext = remoteFrameIter->second.mContext;
+  }
+  else {
+    MaybeInvalidTabContext tc(aContext);
+    if (!tc.IsValid()) {
+      NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
+                               "the child process. (%s)",
+                               tc.GetInvalidReason()).get());
+      return TabId(0);
+    }
+    info.mOpenerTabId = aOpenerTabId;
+    info.mContext = tc.GetTabContext();
+  }
+
+  mUniqueId = ++gTabId;
+  iter->second.mRemoteFrames[mUniqueId] = info;
+
+  return mUniqueId;
+}
+
+void
+ContentProcessManager::DeallocateTabId(const ContentParentId& aChildCpId,
+                                       const TabId& aChildTabId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return;
+  }
+
+  auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
+  if (remoteFrameIter != iter->second.mRemoteFrames.end()) {
+    iter->second.mRemoteFrames.erase(aChildTabId);
+  }
+}
+
+nsTArray<uint64_t>
+ContentProcessManager::GetAppIdsByContentProcess(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<uint64_t> appIdArray;
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return Move(appIdArray);
+  }
+
+  for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
+       remoteFrameIter != iter->second.mRemoteFrames.end();
+       ++remoteFrameIter) {
+    appIdArray.AppendElement(remoteFrameIter->second.mContext.OwnOrContainingAppId());
+  }
+
+  return Move(appIdArray);
+}
+
+nsTArray<TabContext>
+ContentProcessManager::GetTabContextByContentProcess(const ContentParentId& aChildCpId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsTArray<TabContext> tabContextArray;
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return Move(tabContextArray);
+  }
+
+  for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
+       remoteFrameIter != iter->second.mRemoteFrames.end();
+       ++remoteFrameIter) {
+    tabContextArray.AppendElement(remoteFrameIter->second.mContext);
+  }
+
+  return Move(tabContextArray);
+}
+
+bool
+ContentProcessManager::GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
+                                                 const TabId& aChildTabId,
+                                                 /*out*/TabId* aOpenerTabId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  auto iter = mContentParentMap.find(aChildCpId);
+  if (NS_WARN_IF(iter == mContentParentMap.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return false;
+  }
+
+  auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
+  if (NS_WARN_IF(remoteFrameIter == iter->second.mRemoteFrames.end())) {
+    ASSERT_UNLESS_FUZZING();
+    return false;
+  }
+
+  *aOpenerTabId = remoteFrameIter->second.mOpenerTabId;
+
+  return true;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/ContentProcessManager.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_ContentProcessManager_h
+#define mozilla_dom_ContentProcessManager_h
+
+#include <map>
+#include <set>
+#include "mozilla/StaticPtr.h"
+#include "mozilla/dom/TabContext.h"
+#include "mozilla/dom/ipc/IdType.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+class ContentParent;
+
+struct RemoteFrameInfo
+{
+  TabId mOpenerTabId;
+  TabContext mContext;
+};
+
+struct ContentProcessInfo
+{
+  ContentParent* mCp;
+  ContentParentId mParentCpId;
+  std::set<ContentParentId> mChildrenCpId;
+  std::map<TabId, RemoteFrameInfo> mRemoteFrames;
+};
+
+class ContentProcessManager MOZ_FINAL
+{
+public:
+  static ContentProcessManager* GetSingleton();
+  ~ContentProcessManager() {MOZ_COUNT_DTOR(ContentProcessManager);};
+
+  /**
+   * Add a new content process into the map.
+   * If aParentCpId is not 0, it's a nested content process.
+   */
+  void AddContentProcess(ContentParent* aChildCp,
+                         const ContentParentId& aParentCpId = ContentParentId(0));
+  /**
+   * Remove the content process by id.
+   */
+  void RemoveContentProcess(const ContentParentId& aChildCpId);
+  /**
+   * Add a grandchild content process into the map.
+   * aParentCpId must be already added in the map by AddContentProcess().
+   */
+  bool AddGrandchildProcess(const ContentParentId& aParentCpId,
+                            const ContentParentId& aChildCpId);
+  /**
+   * Get the parent process's id by child process's id.
+   * Used to check if a child really belongs to the parent.
+   */
+  bool GetParentProcessId(const ContentParentId& aChildCpId,
+                          /*out*/ ContentParentId* aParentCpId);
+  /**
+   * Return the ContentParent pointer by id.
+   */
+  ContentParent* GetContentProcessById(const ContentParentId& aChildCpId);
+
+  /**
+   * Return a list of all child process's id.
+   */
+  nsTArray<ContentParentId>
+  GetAllChildProcessById(const ContentParentId& aParentCpId);
+
+  /**
+   * Allocate a tab id for the given content process's id.
+   * Used when a content process wants to create a new tab. aOpenerTabId and
+   * aContext are saved in RemoteFrameInfo, which is a part of ContentProcessInfo.
+   * We can use the tab id and process id to locate the TabContext for future use.
+   */
+  TabId AllocateTabId(const TabId& aOpenerTabId,
+                      const IPCTabContext& aContext,
+                      const ContentParentId& aChildCpId);
+
+  /**
+   * Remove the RemoteFrameInfo by the given process and tab id.
+   */
+  void DeallocateTabId(const ContentParentId& aChildCpId,
+                       const TabId& aChildTabId);
+
+  /**
+   * Get all app ids which are inside the given content process.
+   * XXX Currently not used. Plan to be used for bug 1020186.
+   */
+  nsTArray<uint64_t>
+  GetAppIdsByContentProcess(const ContentParentId& aChildCpId);
+
+  /**
+   * Get all TabContext which are inside the given content process.
+   * Used for AppProcessChecker to cehck app status.
+   */
+  nsTArray<TabContext>
+  GetTabContextByContentProcess(const ContentParentId& aChildCpId);
+
+  /**
+   * Query a tab's opener id by the given process and tab id.
+   * XXX Currently not used. Plan to be used for bug 1020179.
+   */
+  bool GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
+                                 const TabId& aChildTabId,
+                                 /*out*/ TabId* aOpenerTabId);
+
+private:
+  static StaticAutoPtr<ContentProcessManager> sSingleton;
+  TabId mUniqueId;
+  std::map<ContentParentId, ContentProcessInfo> mContentParentMap;
+
+  ContentProcessManager() {MOZ_COUNT_CTOR(ContentProcessManager);};
+};
+
+} // namespace dom
+} // namespace mozilla
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/ipc/IdType.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_IdType_h
+#define mozilla_dom_IdType_h
+
+#include "ipc/IPCMessageUtils.h"
+
+namespace IPC {
+template<typename T> struct ParamTraits;
+}
+
+namespace mozilla {
+namespace dom {
+class ContentParent;
+class TabParent;
+
+
+template<typename T>
+class IdType
+{
+
+  friend struct IPC::ParamTraits<IdType<T>>;
+
+public:
+  IdType() : mId(0) {}
+  explicit IdType(uint64_t aId) : mId(aId) {}
+
+  operator uint64_t() const { return mId; }
+
+  IdType& operator=(uint64_t aId)
+  {
+    mId = aId;
+    return *this;
+  }
+
+  bool operator<(const IdType& rhs)
+  {
+    return mId < rhs.mId;
+  }
+private:
+  uint64_t mId;
+};
+
+typedef IdType<TabParent> TabId;
+typedef IdType<ContentParent> ContentParentId;
+
+} // namespace dom
+} // namespace mozilla
+
+namespace IPC {
+
+template<typename T>
+struct ParamTraits<mozilla::dom::IdType<T>>
+{
+  typedef mozilla::dom::IdType<T> paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mId);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mId);
+  }
+};
+
+}
+
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PBrowserOrId.ipdlh
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=c: */
+/* 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 PBrowser;
+
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
+
+namespace mozilla {
+namespace dom {
+
+union PBrowserOrId
+{
+  nullable PBrowser;
+  TabId;
+};
+
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -65,16 +65,18 @@ using struct mozilla::void_t from "ipc/I
 using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::asmjscache::WriteParams from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::AudioChannel from "mozilla/dom/AudioChannelBinding.h";
 using mozilla::dom::AudioChannelState from "AudioChannelCommon.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::dom::quota::PersistenceType from "mozilla/dom/quota/PersistenceType.h";
 using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
 using gfxIntSize from "nsSize.h";
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
+using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 
 union ChromeRegistryItem
 {
     ChromePackage;
     OverrideMapping;
     ResourceMapping;
 };
 
@@ -386,18 +388,18 @@ both:
     // browser element.
     //
     // This allows the parent to prevent a malicious child from escalating its
     // privileges by requesting a PBrowser corresponding to a highly-privileged
     // app; the child can only request privileges for an app which the child has
     // access to (in the form of a TabChild).
     //
     // Keep the last 3 attributes in sync with GetProcessAttributes!
-    async PBrowser(IPCTabContext context, uint32_t chromeFlags,
-                   uint64_t id, bool isForApp, bool isForBrowser);
+    async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
+                   ContentParentId cpId, bool isForApp, bool isForBrowser);
 
     async PBlob(BlobConstructorParams params);
 
     PFileDescriptorSet(FileDescriptor fd);
 
 child:
     /**
      * Enable system-level sandboxing features, if available.  Can
@@ -521,25 +523,26 @@ parent:
      * |id| is a unique ID among all subprocesses.  When |isForApp &&
      * isForBrowser|, we're loading <browser> for an app.  When
      * |isForBrowser|, we're loading <browser>.  When |!isForApp &&
      * !isForBrowser|, we're probably loading <xul:browser remote>.
      *
      * Keep the return values in sync with PBrowser()!
      */
     sync GetProcessAttributes()
-        returns (uint64_t id, bool isForApp, bool isForBrowser);
+        returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
     sync GetXPCOMProcessAttributes()
         returns (bool isOffline, nsString[] dictionaries,
                  ClipboardCapabilities clipboardCaps);
 
     sync CreateChildProcess(IPCTabContext context,
-                            ProcessPriority priority)
-        returns (uint64_t id, bool isForApp, bool isForBrowser);
-    intr BridgeToChildProcess(uint64_t id);
+                            ProcessPriority priority,
+                            TabId openerTabId)
+        returns (ContentParentId cpId, bool isForApp, bool isForBrowser, TabId tabId);
+    intr BridgeToChildProcess(ContentParentId cpId);
 
     /**
      * This call connects the content process to a plugin process. While this
      * call runs, a new PluginModuleParent will be created in the ContentChild
      * via bridging. The corresponding PluginModuleChild will live in the plugin
      * process. We use intr semantics here to ensure that the PluginModuleParent
      * allocation message is dispatched before LoadPlugin returns.
      */
@@ -769,15 +772,23 @@ parent:
     // Use only for testing!
     sync GetFileReferences(PersistenceType persistenceType,
                            nsCString origin,
                            nsString databaseName,
                            int64_t fileId)
       returns (int32_t refCnt, int32_t dBRefCnt, int32_t sliceRefCnt,
                bool result);
 
+    /**
+     * Tell the chrome process there is an creation of PBrowser.
+     * return a system-wise unique Id.
+     */
+    sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
+        returns (TabId tabId);
+    async DeallocateTabId(TabId tabId);
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -9,16 +9,18 @@ include protocol PBrowser;
 include protocol PContent;
 include protocol PJavaScript;
 
 include DOMTypes;
 include JavaScriptTypes;
 include PTabContext;
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
+using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 namespace dom {
 
 /*
  * PContentBridge allows us to represent a parent/child relationship between two
  * child processes.  When a child process wants to open its own child, it asks
  * the root process to create a new process and then bridge them.  The first
@@ -36,18 +38,18 @@ prio(normal upto high) intr protocol PCo
 
 parent:
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
 both:
     // Both the parent and the child can construct the PBrowser.
     // See the comment in PContent::PBrowser().
-    async PBrowser(IPCTabContext context, uint32_t chromeFlags,
-                   uint64_t id, bool isForApp, bool isForBrowser);
+    async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
+                   ContentParentId cpId, bool isForApp, bool isForBrowser);
 
     async PBlob(BlobConstructorParams params);
 
     async PJavaScript();
 
     AsyncMessage(nsString aMessage, ClonedMessageData aData,
                  CpowEntry[] aCpows, Principal aPrincipal);
 };
--- a/dom/ipc/PTabContext.ipdlh
+++ b/dom/ipc/PTabContext.ipdlh
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* 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 PBrowser;
-
+include PBrowserOrId;
 
 using mozilla::layout::ScrollingBehavior from "mozilla/layout/RenderFrameUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 // An IPCTabContext which corresponds to a PBrowser opened by a child when it
 // receives window.open().
@@ -22,17 +22,17 @@ namespace dom {
 // If isBrowserElement is true, the frame's browserFrameOwnerAppId will be equal
 // to the opener's app-id.
 //
 // It's an error to set isBrowserElement == false if opener is a browser
 // element.  Such a PopupIPCTabContext should be rejected by code which receives
 // it.
 struct PopupIPCTabContext
 {
-  PBrowser opener;
+  PBrowserOrId opener;
   bool isBrowserElement;
 };
 
 // An IPCTabContext which corresponds to an app frame.
 struct AppFrameIPCTabContext
 {
   // The ID of the app this frame corresponds to.  May be NO_APP_ID.
   uint32_t ownAppId;
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -467,24 +467,25 @@ ProcessPriorityManagerImpl::Observe(
   return NS_OK;
 }
 
 already_AddRefed<ParticularProcessPriorityManager>
 ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
   ContentParent* aContentParent)
 {
   nsRefPtr<ParticularProcessPriorityManager> pppm;
-  mParticularManagers.Get(aContentParent->ChildID(), &pppm);
+  uint64_t cpId = aContentParent->ChildID();
+  mParticularManagers.Get(cpId, &pppm);
   if (!pppm) {
     pppm = new ParticularProcessPriorityManager(aContentParent);
     pppm->Init();
-    mParticularManagers.Put(aContentParent->ChildID(), pppm);
+    mParticularManagers.Put(cpId, pppm);
 
     FireTestOnlyObserverNotification("process-created",
-      nsPrintfCString("%lld", aContentParent->ChildID()));
+      nsPrintfCString("%lld", cpId));
   }
 
   return pppm.forget();
 }
 
 void
 ProcessPriorityManagerImpl::SetProcessPriority(ContentParent* aContentParent,
                                                ProcessPriority aPriority,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -728,33 +728,34 @@ private:
         mInfo->FireCallback();
         return NS_OK;
     }
 };
 
 StaticRefPtr<TabChild> sPreallocatedTab;
 
 /*static*/
-std::map<uint64_t, nsRefPtr<TabChild> >&
+std::map<TabId, nsRefPtr<TabChild>>&
 TabChild::NestedTabChildMap()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  static std::map<uint64_t, nsRefPtr<TabChild> > sNestedTabChildMap;
+  static std::map<TabId, nsRefPtr<TabChild>> sNestedTabChildMap;
   return sNestedTabChildMap;
 }
 
 /*static*/ void
 TabChild::PreloadSlowThings()
 {
     MOZ_ASSERT(!sPreallocatedTab);
 
     // Pass nullptr to aManager since at this point the TabChild is
     // not connected to any manager. Any attempt to use the TabChild
     // in IPC will crash.
     nsRefPtr<TabChild> tab(new TabChild(nullptr,
+                                        TabId(0),
                                         TabContext(), /* chromeFlags */ 0));
     if (!NS_SUCCEEDED(tab->Init()) ||
         !tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) {
         return;
     }
     // Just load and compile these scripts, but don't run them.
     tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
     // Load, compile, and run these scripts.
@@ -775,41 +776,44 @@ TabChild::PreloadSlowThings()
     }
 
     sPreallocatedTab = tab;
     ClearOnShutdown(&sPreallocatedTab);
 }
 
 /*static*/ already_AddRefed<TabChild>
 TabChild::Create(nsIContentChild* aManager,
+                 const TabId& aTabId,
                  const TabContext &aContext,
                  uint32_t aChromeFlags)
 {
     if (sPreallocatedTab &&
         sPreallocatedTab->mChromeFlags == aChromeFlags &&
         aContext.IsBrowserOrApp()) {
 
         nsRefPtr<TabChild> child = sPreallocatedTab.get();
         sPreallocatedTab = nullptr;
 
         MOZ_ASSERT(!child->mTriedBrowserInit);
 
         child->mManager = aManager;
+        child->SetTabId(aTabId);
         child->SetTabContext(aContext);
         child->NotifyTabContextUpdated();
         return child.forget();
     }
 
-    nsRefPtr<TabChild> iframe = new TabChild(aManager,
+    nsRefPtr<TabChild> iframe = new TabChild(aManager, aTabId,
                                              aContext, aChromeFlags);
     return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
 }
 
 
 TabChild::TabChild(nsIContentChild* aManager,
+                   const TabId& aTabId,
                    const TabContext& aContext,
                    uint32_t aChromeFlags)
   : TabContext(aContext)
   , mRemoteFrame(nullptr)
   , mManager(aManager)
   , mChromeFlags(aChromeFlags)
   , mLayersId(0)
   , mOuterRect(0, 0, 0, 0)
@@ -823,25 +827,31 @@ TabChild::TabChild(nsIContentChild* aMan
   , mUpdateHitRegion(false)
   , mPendingTouchPreventedResponse(false)
   , mPendingTouchPreventedBlockId(0)
   , mTouchEndCancelled(false)
   , mEndTouchIsClick(false)
   , mIgnoreKeyPressEvent(false)
   , mActiveElementManager(new ActiveElementManager())
   , mHasValidInnerSize(false)
-  , mUniqueId(0)
   , mDestroyed(false)
+  , mUniqueId(aTabId)
 {
   if (!sActiveDurationMsSet) {
     Preferences::AddIntVarCache(&sActiveDurationMs,
                                 "ui.touch_activation.duration_ms",
                                 sActiveDurationMs);
     sActiveDurationMsSet = true;
   }
+
+  // preloaded TabChild should not be added to child map
+  if (mUniqueId) {
+    MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
+    NestedTabChildMap()[mUniqueId] = this;
+  }
 }
 
 NS_IMETHODIMP
 TabChild::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
   aEvent->GetType(eventType);
   if (eventType.EqualsLiteral("DOMMetaAdded")) {
@@ -1429,36 +1439,46 @@ TabChild::BrowserFrameProvideWindow(nsID
                                     nsIURI* aURI,
                                     const nsAString& aName,
                                     const nsACString& aFeatures,
                                     bool* aWindowIsNew,
                                     nsIDOMWindow** aReturn)
 {
   *aReturn = nullptr;
 
-  nsRefPtr<TabChild> newChild =
-      new TabChild(ContentChild::GetSingleton(),
-                   /* TabContext */ *this, /* chromeFlags */ 0);
-  if (!NS_SUCCEEDED(newChild->Init())) {
-      return NS_ERROR_ABORT;
-  }
+  ContentChild* cc = ContentChild::GetSingleton();
+  const TabId openerTabId = GetTabId();
 
   // We must use PopupIPCTabContext here; ContentParent will not accept the
   // result of this->AsIPCTabContext() (which will be a
   // BrowserFrameIPCTabContext or an AppFrameIPCTabContext), for security
   // reasons.
   PopupIPCTabContext context;
-  context.openerChild() = this;
+  context.opener() = openerTabId;
   context.isBrowserElement() = IsBrowserElement();
 
-  ContentChild* cc = static_cast<ContentChild*>(Manager());
+  IPCTabContext ipcContext(context, mScrolling);
+
+  TabId tabId;
+  cc->SendAllocateTabId(openerTabId,
+                        ipcContext,
+                        cc->GetID(),
+                        &tabId);
+
+  nsRefPtr<TabChild> newChild = new TabChild(ContentChild::GetSingleton(), tabId,
+                                             /* TabContext */ *this, /* chromeFlags */ 0);
+  if (NS_FAILED(newChild->Init())) {
+    return NS_ERROR_ABORT;
+  }
+
+  context.opener() = this;
   unused << Manager()->SendPBrowserConstructor(
       // We release this ref in DeallocPBrowserChild
       nsRefPtr<TabChild>(newChild).forget().take(),
-      IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
+      tabId, IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
       cc->GetID(), cc->IsForApp(), cc->IsForBrowser());
 
   nsAutoCString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
 
   NS_ConvertUTF8toUTF16 url(spec);
@@ -1558,18 +1578,18 @@ TabChild::ActorDestroy(ActorDestroyReaso
     static_cast<nsFrameMessageManager*>
       (mTabChildGlobal->mMessageManager.get())->Disconnect();
     mTabChildGlobal->mMessageManager = nullptr;
   }
 
   CompositorChild* compositorChild = static_cast<CompositorChild*>(CompositorChild::Get());
   compositorChild->CancelNotifyAfterRemotePaint(this);
 
-  if (Id() != 0) {
-    NestedTabChildMap().erase(Id());
+  if (GetTabId() != 0) {
+    NestedTabChildMap().erase(GetTabId());
   }
 }
 
 TabChild::~TabChild()
 {
     DestroyWindow();
 
     nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -29,16 +29,17 @@
 #include "nsITooltipListener.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "nsIWebBrowserChrome3.h"
+#include "mozilla/dom/ipc/IdType.h"
 
 class nsICachedFileDescriptorListener;
 class nsIDOMWindowUtils;
 
 namespace mozilla {
 namespace layout {
 class RenderFrameChild;
 }
@@ -249,48 +250,35 @@ class TabChild MOZ_FINAL : public TabChi
                            public nsITooltipListener
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
     typedef mozilla::layout::RenderFrameChild RenderFrameChild;
     typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
     typedef mozilla::layers::ActiveElementManager ActiveElementManager;
 
 public:
-    static std::map<uint64_t, nsRefPtr<TabChild> >& NestedTabChildMap();
+    static std::map<TabId, nsRefPtr<TabChild>>& NestedTabChildMap();
 
 public:
     /** 
      * This is expected to be called off the critical path to content
      * startup.  This is an opportunity to load things that are slow
      * on the critical path.
      */
     static void PreloadSlowThings();
 
     /** Return a TabChild with the given attributes. */
     static already_AddRefed<TabChild>
-    Create(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags);
 
     bool IsRootContentDocument();
 
-    const uint64_t Id() const {
-        return mUniqueId;
-    }
-
-    static uint64_t
-    GetTabChildId(TabChild* aTabChild)
-    {
-        MOZ_ASSERT(NS_IsMainThread());
-        if (aTabChild->Id() != 0) {
-            return aTabChild->Id();
-        }
-        static uint64_t sId = 0;
-        sId++;
-        aTabChild->mUniqueId = sId;
-        NestedTabChildMap()[sId] = aTabChild;
-        return sId;
+    const TabId GetTabId() const {
+      MOZ_ASSERT(mUniqueId != 0);
+      return mUniqueId;
     }
 
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIEMBEDDINGSITEWINDOW
     NS_DECL_NSIWEBBROWSERCHROMEFOCUS
     NS_DECL_NSIINTERFACEREQUESTOR
@@ -514,17 +502,20 @@ private:
     /**
      * Create a new TabChild object.
      *
      * |aOwnOrContainingAppId| is the app-id of our frame or of the closest app
      * frame in the hierarchy which contains us.
      *
      * |aIsBrowserElement| indicates whether we're a browser (but not an app).
      */
-    TabChild(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    TabChild(nsIContentChild* aManager,
+             const TabId& aTabId,
+             const TabContext& aContext,
+             uint32_t aChromeFlags);
 
     nsresult Init();
 
     class DelayedFireSingleTapEvent;
     class DelayedFireContextMenuEvent;
 
     // Notify others that our TabContext has been updated.  (At the moment, this
     // sets the appropriate app-id and is-browser flags on our docshell.)
@@ -562,16 +553,24 @@ private:
                               bool* aWindowIsNew,
                               nsIDOMWindow** aReturn);
 
     bool HasValidInnerSize();
 
     void SendPendingTouchPreventedResponse(bool aPreventDefault,
                                            const ScrollableLayerGuid& aGuid);
 
+    void SetTabId(const TabId& aTabId)
+    {
+      MOZ_ASSERT(mUniqueId == 0);
+
+      mUniqueId = aTabId;
+      NestedTabChildMap()[mUniqueId] = this;
+    }
+
     class CachedFileDescriptorInfo;
     class CachedFileDescriptorCallbackRunnable;
 
     TextureFactoryIdentifier mTextureFactoryIdentifier;
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIWidget> mWidget;
     nsCOMPtr<nsIURI> mLastURI;
     RenderFrameChild* mRemoteFrame;
@@ -605,18 +604,18 @@ private:
     void FireSingleTapEvent(LayoutDevicePoint aPoint);
 
     bool mTouchEndCancelled;
     bool mEndTouchIsClick;
 
     bool mIgnoreKeyPressEvent;
     nsRefPtr<ActiveElementManager> mActiveElementManager;
     bool mHasValidInnerSize;
-    uint64_t mUniqueId;
     bool mDestroyed;
+    TabId mUniqueId;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 }
 }
 
 #endif // mozilla_dom_TabChild_h
--- a/dom/ipc/TabContext.cpp
+++ b/dom/ipc/TabContext.cpp
@@ -251,29 +251,34 @@ MaybeInvalidTabContext::MaybeInvalidTabC
   uint32_t containingAppId = NO_APP_ID;
 
   const IPCTabAppBrowserContext& appBrowser = aParams.appBrowserContext();
   switch(appBrowser.type()) {
     case IPCTabAppBrowserContext::TPopupIPCTabContext: {
       const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext();
 
       TabContext *context;
-      if (ipcContext.openerParent()) {
-        context = static_cast<TabParent*>(ipcContext.openerParent());
+      if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) {
+        context = static_cast<TabParent*>(ipcContext.opener().get_PBrowserParent());
         if (context->IsBrowserElement() && !ipcContext.isBrowserElement()) {
           // If the TabParent corresponds to a browser element, then it can only
           // open other browser elements, for security reasons.  We should have
           // checked this before calling the TabContext constructor, so this is
           // a fatal error.
           mInvalidReason = "Child is-browser process tried to "
                            "open a non-browser tab.";
           return;
         }
-      } else if (ipcContext.openerChild()) {
-        context = static_cast<TabChild*>(ipcContext.openerChild());
+      } else if (ipcContext.opener().type() == PBrowserOrId::TPBrowserChild) {
+        context = static_cast<TabChild*>(ipcContext.opener().get_PBrowserChild());
+      } else if (ipcContext.opener().type() == PBrowserOrId::TTabId) {
+        // We should never get here because this PopupIPCTabContext is only
+        // used for allocating a new tab id, not for allocating a PBrowser.
+        mInvalidReason = "Child process tried to open an tab without the opener information.";
+        return;
       } else {
         // This should be unreachable because PopupIPCTabContext::opener is not a
         // nullable field.
         mInvalidReason = "PopupIPCTabContext::opener was null (?!).";
         return;
       }
 
       // Browser elements can't nest other browser elements.  So if
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -213,17 +213,20 @@ TabParent* sEventCapturer;
 TabParent *TabParent::mIMETabParent = nullptr;
 
 NS_IMPL_ISUPPORTS(TabParent,
                   nsITabParent,
                   nsIAuthPromptProvider,
                   nsISecureBrowserUI,
                   nsISupportsWeakReference)
 
-TabParent::TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags)
+TabParent::TabParent(nsIContentParent* aManager,
+                     const TabId& aTabId,
+                     const TabContext& aContext,
+                     uint32_t aChromeFlags)
   : TabContext(aContext)
   , mFrameElement(nullptr)
   , mIMESelectionAnchor(0)
   , mIMESelectionFocus(0)
   , mIMEComposing(false)
   , mIMECompositionEnding(false)
   , mIMECompositionStart(0)
   , mIMESeqno(0)
@@ -237,16 +240,17 @@ TabParent::TabParent(nsIContentParent* a
   , mShown(false)
   , mUpdatedDimensions(false)
   , mManager(aManager)
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mAppPackageFileDescriptorSent(false)
   , mSendOfflineStatus(true)
   , mChromeFlags(aChromeFlags)
+  , mTabId(aTabId)
 {
   MOZ_ASSERT(aManager);
 }
 
 TabParent::~TabParent()
 {
 }
 
@@ -313,17 +317,23 @@ TabParent::Destroy()
   mMarkedDestroying = true;
 }
 
 bool
 TabParent::Recv__delete__()
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     Manager()->AsContentParent()->NotifyTabDestroyed(this, mMarkedDestroying);
+    ContentParent::DeallocateTabId(mTabId,
+                                   Manager()->AsContentParent()->ChildID());
   }
+  else {
+    ContentParent::DeallocateTabId(mTabId, ContentParentId(0));
+  }
+
   return true;
 }
 
 void
 TabParent::ActorDestroy(ActorDestroyReason why)
 {
   if (sEventCapturer == this) {
     sEventCapturer = nullptr;
@@ -1645,16 +1655,26 @@ TabParent::GetFrom(nsIContent* aContent)
   nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aContent);
   if (!loaderOwner) {
     return nullptr;
   }
   nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
   return GetFrom(frameLoader);
 }
 
+/*static*/ TabId
+TabParent::GetTabIdFrom(nsIDocShell *docShell)
+{
+  nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
+  if (tabChild) {
+    return static_cast<TabChild*>(tabChild.get())->GetTabId();
+  }
+  return TabId(0);
+}
+
 RenderFrameParent*
 TabParent::GetRenderFrame()
 {
   if (ManagedPRenderFrameParent().IsEmpty()) {
     return nullptr;
   }
   return static_cast<RenderFrameParent*>(ManagedPRenderFrameParent()[0]);
 }
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
+#include "mozilla/dom/ipc/IdType.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsWeakReference.h"
 #include "Units.h"
@@ -23,16 +24,17 @@
 
 class nsFrameLoader;
 class nsIContent;
 class nsIPrincipal;
 class nsIURI;
 class nsIWidget;
 class nsILoadContext;
 class CpowHolder;
+class nsIDocShell;
 
 namespace mozilla {
 
 namespace layers {
 struct FrameMetrics;
 struct TextureFactoryIdentifier;
 }
 
@@ -62,17 +64,20 @@ class TabParent : public PBrowserParent
     typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
 
     virtual ~TabParent();
 
 public:
     // nsITabParent
     NS_DECL_NSITABPARENT
 
-    TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags);
+    TabParent(nsIContentParent* aManager,
+              const TabId& aTabId,
+              const TabContext& aContext,
+              uint32_t aChromeFlags);
     Element* GetOwnerElement() const { return mFrameElement; }
     void SetOwnerElement(Element* aElement);
 
     /**
      * Get the mozapptype attribute from this TabParent's owner DOM element.
      */
     void GetAppType(nsAString& aOut);
 
@@ -319,27 +324,33 @@ public:
 
     static TabParent *GetIMETabParent() { return mIMETabParent; }
     bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
     bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event);
     bool SendSelectionEvent(mozilla::WidgetSelectionEvent& event);
 
     static TabParent* GetFrom(nsFrameLoader* aFrameLoader);
     static TabParent* GetFrom(nsIContent* aContent);
+    static TabId GetTabIdFrom(nsIDocShell* docshell);
 
     nsIContentParent* Manager() { return mManager; }
 
     /**
      * Let managees query if Destroy() is already called so they don't send out
      * messages when the PBrowser actor is being destroyed.
      */
     bool IsDestroyed() const { return mIsDestroyed; }
 
     already_AddRefed<nsIWidget> GetWidget() const;
 
+    const TabId GetTabId() const
+    {
+      return mTabId;
+    }
+
 protected:
     bool ReceiveMessage(const nsString& aMessage,
                         bool aSync,
                         const StructuredCloneData* aCloneData,
                         CpowHolder* aCpows,
                         nsIPrincipal* aPrincipal,
                         InfallibleTArray<nsString>* aJSONRetVal = nullptr);
 
@@ -436,14 +447,16 @@ private:
 
     // Whether we need to send the offline status to the TabChild
     // This is true, until the first call of LoadURL
     bool mSendOfflineStatus;
 
     uint32_t mChromeFlags;
 
     nsCOMPtr<nsILoadContext> mLoadContext;
+
+    TabId mTabId;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -6,25 +6,27 @@
 
 EXPORTS += [
     'nsICachedFileDescriptorListener.h',
 ]
 
 EXPORTS.mozilla.dom.ipc += [
     'BlobChild.h',
     'BlobParent.h',
+    'IdType.h',
     'nsIRemoteBlob.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'ContentBridgeChild.h',
     'ContentBridgeParent.h',
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
+    'ContentProcessManager.h',
     'CPOWManagerGetter.h',
     'CrashReporterChild.h',
     'CrashReporterParent.h',
     'FilePickerParent.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
     'StructuredCloneUtils.h',
@@ -42,16 +44,17 @@ EXPORTS.mozilla += [
 
 UNIFIED_SOURCES += [
     'AppProcessChecker.cpp',
     'ColorPickerParent.cpp',
     'ContentBridgeChild.cpp',
     'ContentBridgeParent.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
+    'ContentProcessManager.cpp',
     'CrashReporterParent.cpp',
     'FilePickerParent.cpp',
     'nsIContentChild.cpp',
     'nsIContentParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
     'ScreenManagerParent.cpp',
@@ -72,16 +75,17 @@ SOURCES += [
     'CrashReporterChild.cpp',
 ]
 
 IPDL_SOURCES += [
     'DOMTypes.ipdlh',
     'PBlob.ipdl',
     'PBlobStream.ipdl',
     'PBrowser.ipdl',
+    'PBrowserOrId.ipdlh',
     'PColorPicker.ipdl',
     'PContent.ipdl',
     'PContentBridge.ipdl',
     'PContentPermission.ipdlh',
     'PContentPermissionRequest.ipdl',
     'PCrashReporter.ipdl',
     'PCycleCollectWithLogs.ipdl',
     'PDocumentRenderer.ipdl',
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -45,36 +45,37 @@ nsIContentChild::AllocPJavaScriptChild()
 bool
 nsIContentChild::DeallocPJavaScriptChild(PJavaScriptChild* aChild)
 {
   static_cast<JavaScriptChild*>(aChild)->decref();
   return true;
 }
 
 PBrowserChild*
-nsIContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
+nsIContentChild::AllocPBrowserChild(const TabId& aTabId,
+                                    const IPCTabContext& aContext,
                                     const uint32_t& aChromeFlags,
-                                    const uint64_t& aID,
+                                    const ContentParentId& aCpID,
                                     const bool& aIsForApp,
                                     const bool& aIsForBrowser)
 {
   // We'll happily accept any kind of IPCTabContext here; we don't need to
   // check that it's of a certain type for security purposes, because we
   // believe whatever the parent process tells us.
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
                              "the parent process. (%s)  Crashing...",
                              tc.GetInvalidReason()).get());
     MOZ_CRASH("Invalid TabContext received from the parent process.");
   }
 
   nsRefPtr<TabChild> child =
-    TabChild::Create(this, tc.GetTabContext(), aChromeFlags);
+    TabChild::Create(this, aTabId, tc.GetTabContext(), aChromeFlags);
 
   // The ref here is released in DeallocPBrowserChild.
   return child.forget().take();
 }
 
 bool
 nsIContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
 {
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -2,16 +2,18 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_nsIContentChild_h
 #define mozilla_dom_nsIContentChild_h
 
+#include "mozilla/dom/ipc/IdType.h"
+
 #include "nsISupports.h"
 #include "nsTArrayForwardDeclare.h"
 #include "mozilla/dom/CPOWManagerGetter.h"
 
 #define NS_ICONTENTCHILD_IID                                    \
   { 0x4eed2e73, 0x94ba, 0x48a8,                                 \
     { 0xa2, 0xd1, 0xa5, 0xed, 0x86, 0xd7, 0xbb, 0xe4 } }
 
@@ -47,28 +49,30 @@ public:
   BlobChild* GetOrCreateActorForBlob(File* aBlob);
 
   virtual PBlobChild* SendPBlobConstructor(
     PBlobChild* aActor,
     const BlobConstructorParams& aParams) = 0;
 
   virtual bool
   SendPBrowserConstructor(PBrowserChild* aActor,
+                          const TabId& aTabId,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
-                          const uint64_t& aID,
+                          const ContentParentId& aCpID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) = 0;
 protected:
   virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild();
   virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*);
 
-  virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
+  virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
+                                            const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const uint64_t& aID,
+                                            const ContentParentId& aCpId,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser);
   virtual bool DeallocPBrowserChild(PBrowserChild*);
 
   virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams);
 
   virtual bool DeallocPBlobChild(PBlobChild* aActor);
 
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -19,16 +19,23 @@
 
 #include "JavaScriptParent.h"
 #include "nsFrameMessageManager.h"
 #include "nsIJSRuntimeService.h"
 #include "nsPrintfCString.h"
 
 using namespace mozilla::jsipc;
 
+// XXX need another bug to move this to a common header.
+#ifdef DISABLE_ASSERTS_FOR_FUZZING
+#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
+#else
+#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
+#endif
+
 namespace mozilla {
 namespace dom {
 
 nsIContentParent::nsIContentParent()
 {
   mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
 }
 
@@ -69,65 +76,70 @@ nsIContentParent::CanOpenBrowser(const I
 {
   const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
 
   // We don't trust the IPCTabContext we receive from the child, so we'll bail
   // if we receive an IPCTabContext that's not a PopupIPCTabContext.
   // (PopupIPCTabContext lets the child process prove that it has access to
   // the app it's trying to open.)
   if (appBrowser.type() != IPCTabAppBrowserContext::TPopupIPCTabContext) {
-    NS_ERROR("Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
+    ASSERT_UNLESS_FUZZING("Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
     return false;
   }
 
   const PopupIPCTabContext& popupContext = appBrowser.get_PopupIPCTabContext();
-  TabParent* opener = static_cast<TabParent*>(popupContext.openerParent());
+  if (popupContext.opener().type() != PBrowserOrId::TPBrowserParent) {
+    ASSERT_UNLESS_FUZZING("Unexpected PopupIPCTabContext type.  Aborting AllocPBrowserParent.");
+    return false;
+  }
+
+  auto opener = static_cast<TabParent*>(popupContext.opener().get_PBrowserParent());
   if (!opener) {
-    NS_ERROR("Got null opener from child; aborting AllocPBrowserParent.");
+    ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent.");
     return false;
   }
 
   // Popup windows of isBrowser frames must be isBrowser if the parent
   // isBrowser.  Allocating a !isBrowser frame with same app ID would allow
   // the content to access data it's not supposed to.
   if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
-    NS_ERROR("Child trying to escalate privileges!  Aborting AllocPBrowserParent.");
+    ASSERT_UNLESS_FUZZING("Child trying to escalate privileges!  Aborting AllocPBrowserParent.");
     return false;
   }
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext.  (%s)  "
                              "Aborting AllocPBrowserParent.",
                              tc.GetInvalidReason()).get());
     return false;
   }
 
   return true;
 }
 
 PBrowserParent*
-nsIContentParent::AllocPBrowserParent(const IPCTabContext& aContext,
+nsIContentParent::AllocPBrowserParent(const TabId& aTabId,
+                                      const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
-                                      const uint64_t& aId,
+                                      const ContentParentId& aCpId,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
-  unused << aChromeFlags;
-  unused << aId;
+  unused << aCpId;
   unused << aIsForApp;
   unused << aIsForBrowser;
 
   if (!CanOpenBrowser(aContext)) {
     return nullptr;
   }
 
   MaybeInvalidTabContext tc(aContext);
   MOZ_ASSERT(tc.IsValid());
-  TabParent* parent = new TabParent(this, tc.GetTabContext(), aChromeFlags);
+  TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(), aChromeFlags);
 
   // We release this ref in DeallocPBrowserParent()
   NS_ADDREF(parent);
   return parent;
 }
 
 bool
 nsIContentParent::DeallocPBrowserParent(PBrowserParent* aFrame)
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -2,16 +2,18 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_nsIContentParent_h
 #define mozilla_dom_nsIContentParent_h
 
+#include "mozilla/dom/ipc/IdType.h"
+
 #include "nsFrameMessageManager.h"
 #include "nsISupports.h"
 #include "mozilla/dom/CPOWManagerGetter.h"
 
 #define NS_ICONTENTPARENT_IID                                   \
   { 0xeeec9ebf, 0x8ecf, 0x4e38,                                 \
     { 0x81, 0xda, 0xb7, 0x34, 0x13, 0x7e, 0xac, 0xf3 } }
 
@@ -44,45 +46,47 @@ class nsIContentParent : public nsISuppo
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTPARENT_IID)
 
   nsIContentParent();
 
   BlobParent* GetOrCreateActorForBlob(File* aBlob);
 
-  virtual uint64_t ChildID() = 0;
+  virtual ContentParentId ChildID() = 0;
   virtual bool IsForApp() = 0;
   virtual bool IsForBrowser() = 0;
 
   virtual PBlobParent* SendPBlobConstructor(
     PBlobParent* aActor,
     const BlobConstructorParams& aParams) NS_WARN_UNUSED_RESULT = 0;
 
   virtual PBrowserParent* SendPBrowserConstructor(
     PBrowserParent* actor,
+    const TabId& aTabId,
     const IPCTabContext& context,
     const uint32_t& chromeFlags,
-    const uint64_t& aId,
+    const ContentParentId& aCpId,
     const bool& aIsForApp,
     const bool& aIsForBrowser) NS_WARN_UNUSED_RESULT = 0;
 
   virtual bool IsContentParent() { return false; }
   ContentParent* AsContentParent();
 
 protected: // methods
   bool CanOpenBrowser(const IPCTabContext& aContext);
 
 protected: // IPDL methods
   virtual mozilla::jsipc::PJavaScriptParent* AllocPJavaScriptParent();
   virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*);
 
-  virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext,
+  virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
+                                              const IPCTabContext& aContext,
                                               const uint32_t& aChromeFlags,
-                                              const uint64_t& aId,
+                                              const ContentParentId& aCpId,
                                               const bool& aIsForApp,
                                               const bool& aIsForBrowser);
   virtual bool DeallocPBrowserParent(PBrowserParent* frame);
 
   virtual PBlobParent* AllocPBlobParent(const BlobConstructorParams& aParams);
 
   virtual bool DeallocPBlobParent(PBlobParent* aActor);
 
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -64,17 +64,17 @@ public:
     return InitDecoder(mSurfaceTexture->JavaSurface());
   }
 
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE {
     mp4_demuxer::AnnexB::ConvertSample(aSample, mConfig.annex_b);
     return MediaCodecDataDecoder::Input(aSample);
   }
 
-  virtual nsresult PostOutput(BufferInfo* aInfo, Microseconds aDuration) MOZ_OVERRIDE {
+  virtual nsresult PostOutput(BufferInfo* aInfo, MediaFormat* aFormat, Microseconds aDuration) MOZ_OVERRIDE {
     VideoInfo videoInfo;
     videoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
 
     bool isSync = false;
     if (MediaCodec::getBUFFER_FLAG_SYNC_FRAME() & aInfo->getFlags()) {
       isSync = true;
     }
 
@@ -101,44 +101,39 @@ public:
 protected:
   layers::ImageContainer* mImageContainer;
   const mp4_demuxer::VideoDecoderConfig& mConfig;
   nsRefPtr<AndroidSurfaceTexture> mSurfaceTexture;
 };
 
 class AudioDataDecoder : public MediaCodecDataDecoder {
 public:
-  AudioDataDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
-                   MediaFormat* aFormat, MediaDataDecoderCallback* aCallback)
-  : MediaCodecDataDecoder(MediaData::Type::AUDIO_SAMPLES, aConfig.mime_type, aFormat, aCallback)
-  , mConfig(aConfig)
+  AudioDataDecoder(const char* aMimeType, MediaFormat* aFormat, MediaDataDecoderCallback* aCallback)
+  : MediaCodecDataDecoder(MediaData::Type::AUDIO_SAMPLES, aMimeType, aFormat, aCallback)
   {
-    MOZ_ASSERT(mConfig.bits_per_sample == 16, "We only support 16-bit audio");
   }
 
-  nsresult Output(BufferInfo* aInfo, void* aBuffer, Microseconds aDuration) {
+  nsresult Output(BufferInfo* aInfo, void* aBuffer, MediaFormat* aFormat, Microseconds aDuration) {
     // The output on Android is always 16-bit signed
 
-    uint32_t numChannels = mConfig.channel_count;
+    uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_STRING("channel-count"));
+    uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_STRING("sample-rate"));
     uint32_t numFrames = (aInfo->getSize() / numChannels) / 2;
 
     AudioDataValue* audio = new AudioDataValue[aInfo->getSize()];
     PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), aInfo->getSize());
 
     mCallback->Output(new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
                                     aDuration,
                                     numFrames,
                                     audio,
                                     numChannels,
-                                    mConfig.samples_per_second));
+                                    sampleRate));
     return NS_OK;
   }
-
-protected:
-  const mp4_demuxer::AudioDecoderConfig& mConfig;
 };
 
 
 bool AndroidDecoderModule::SupportsAudioMimeType(const char* aMimeType) {
   JNIEnv* env = GetJNIForThread();
   MediaCodec* decoder = CreateDecoder(env, aMimeType);
   bool supports = (decoder != nullptr);
   delete decoder;
@@ -176,16 +171,17 @@ AndroidDecoderModule::CreateH264Decoder(
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                                          MediaTaskQueue* aAudioTaskQueue,
                                          MediaDataDecoderCallback* aCallback)
 {
+  MOZ_ASSERT(aConfig.bits_per_sample == 16, "We only handle 16-bit audio!");
 
   nsAutoString mimeType;
   mimeType.AssignASCII(aConfig.mime_type);
 
   jobject jFormat = MediaFormat::CreateAudioFormat(mimeType,
                                                    aConfig.samples_per_second,
                                                    aConfig.channel_count);
 
@@ -211,17 +207,17 @@ AndroidDecoderModule::CreateAudioDecoder
     env->DeleteLocalRef(buffer);
   }
 
   if (mimeType.EqualsLiteral("audio/mp4a-latm")) {
     format->SetInteger(NS_LITERAL_STRING("is-adts"), 1);
   }
 
   nsRefPtr<MediaDataDecoder> decoder =
-    new AudioDataDecoder(aConfig, format, aCallback);
+    new AudioDataDecoder(aConfig.mime_type, format, aCallback);
 
   return decoder.forget();
 
 }
 
 
 nsresult AndroidDecoderModule::Shutdown()
 {
@@ -297,16 +293,18 @@ nsresult MediaCodecDataDecoder::InitDeco
 
 void MediaCodecDataDecoder::DecoderLoop()
 {
   bool outputDone = false;
 
   JNIEnv* env = GetJNIForThread();
   mp4_demuxer::MP4Sample* sample = nullptr;
 
+  nsAutoPtr<MediaFormat> outputFormat;
+
   for (;;) {
     {
       MonitorAutoLock lock(mMonitor);
       while (!mStopping && !mDraining && mQueue.empty()) {
         if (mQueue.empty()) {
           // We could be waiting here forever if we don't signal that we need more input
           mCallback->InputExhausted();
         }
@@ -365,17 +363,17 @@ void MediaCodecDataDecoder::DecoderLoop(
 
       int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT);
       if (outputStatus == MediaCodec::getINFO_TRY_AGAIN_LATER()) {
         // We might want to call mCallback->InputExhausted() here, but there seems to be
         // some possible bad interactions here with the threading
       } else if (outputStatus == MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED()) {
         ResetOutputBuffers();
       } else if (outputStatus == MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED()) {
-        // Don't care, we use SurfaceTexture for video
+        outputFormat = new MediaFormat(mDecoder->GetOutputFormat(), GetJNIForThread());
       } else if (outputStatus < 0) {
         printf_stderr("unknown error from decoder! %d\n", outputStatus);
         mCallback->Error();
       } else {
         // We have a valid buffer index >= 0 here
         if (bufferInfo.getFlags() & MediaCodec::getBUFFER_FLAG_END_OF_STREAM()) {
           outputDone = true;
         }
@@ -387,23 +385,23 @@ void MediaCodecDataDecoder::DecoderLoop(
           duration = mDurations.front();
           mDurations.pop();
         }
 
         jobject buffer = env->GetObjectArrayElement(mOutputBuffers, outputStatus);
         if (buffer) {
           // The buffer will be null on Android L if we are decoding to a Surface
           void* directBuffer = env->GetDirectBufferAddress(buffer);
-          Output(&bufferInfo, directBuffer, duration);
+          Output(&bufferInfo, directBuffer, outputFormat, duration);
         }
 
         // The Surface will be updated at this point (for video)
         mDecoder->ReleaseOutputBuffer(outputStatus, true);
 
-        PostOutput(&bufferInfo, duration);
+        PostOutput(&bufferInfo, outputFormat, duration);
 
         if (buffer) {
           env->DeleteLocalRef(buffer);
         }
       }
     }
   }
 
--- a/dom/media/fmp4/android/AndroidDecoderModule.h
+++ b/dom/media/fmp4/android/AndroidDecoderModule.h
@@ -89,18 +89,18 @@ protected:
   bool mDraining;
   bool mStopping;
 
   SampleQueue mQueue;
   std::queue<Microseconds> mDurations;
 
   virtual nsresult InitDecoder(jobject aSurface = nullptr);
 
-  virtual nsresult Output(mozilla::widget::android::BufferInfo* aInfo, void* aBuffer, Microseconds aDuration) { return NS_OK; }
-  virtual nsresult PostOutput(mozilla::widget::android::BufferInfo* aInfo, Microseconds aDuration) { return NS_OK; }
+  virtual nsresult Output(mozilla::widget::android::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
+  virtual nsresult PostOutput(mozilla::widget::android::BufferInfo* aInfo, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
 
   void ResetInputBuffers();
   void ResetOutputBuffers();
 
   void DecoderLoop();
   virtual void ClearQueue();
 };
 
--- a/dom/media/test/test_reset_src.html
+++ b/dom/media/test/test_reset_src.html
@@ -36,16 +36,17 @@ function onLoadedMetadata_Audio(e) {
   try {
     c.drawImage(t, 0, 0, t.videoHeight, t.videoWidth);
   } catch (e) {
     ok(true, t.name + ": Trying to draw to a canvas should throw, since we don't have a frame anymore");
     finish(t);
     return;
   }
   ok(false, t.name + ": We should not succeed to draw a video frame on the canvas.");
+  finish(t);
 }
 
 function onTimeUpdate_Video(e) {
   var t = e.target;
   if (t.currentTime < t.duration / 4) {
     return;
   }
   t.removeEventListener("timeupdate", onTimeUpdate_Video);
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -96,16 +96,21 @@ public:
     MaybeSomething(aArg, &Promise::MaybeResolve);
   }
 
   inline void MaybeReject(nsresult aArg) {
     MOZ_ASSERT(NS_FAILED(aArg));
     MaybeSomething(aArg, &Promise::MaybeReject);
   }
 
+  inline void MaybeReject(ErrorResult& aArg) {
+    MOZ_ASSERT(aArg.Failed());
+    MaybeSomething(aArg, &Promise::MaybeReject);
+  }
+
   void MaybeReject(const nsRefPtr<MediaStreamError>& aArg);
 
   // DO NOT USE MaybeRejectBrokenly with in new code.  Promises should be
   // rejected with Error instances.
   // Note: MaybeRejectBrokenly is a template so we can use it with DOMError
   // without instantiating the DOMError specialization of MaybeSomething in
   // every translation unit that includes this header, because that would
   // require use to include DOMError.h either here or in all those translation
--- a/dom/tests/mochitest/pointerlock/file_pointerlock-api.html
+++ b/dom/tests/mochitest/pointerlock/file_pointerlock-api.html
@@ -29,26 +29,28 @@
         hasRequestPointerLock = false,
         pointerLockChangeEventFired = false,
         pointerUnlocked = false,
         pointerLocked = false,
         hasExitPointerLock = false,
         pointerLockElement = false,
         hasMovementX = false,
         hasMovementY = false;
+        gotContextMenuEvent = false;
 
       function runTests () {
         ok(hasRequestPointerLock, "Element should have mozRequestPointerLock.");
         ok(pointerLockChangeEventFired, "pointerlockchange event should fire.");
         ok(pointerUnlocked, "Should be able to unlock pointer locked element.");
         ok(pointerLocked, "Requested element should be able to lock.");
         ok(hasExitPointerLock, "Document should have mozExitPointerLock");
         ok(pointerLockElement, "Document should keep track of correct pointer locked element");
         ok(hasMovementX, "Mouse Event should have mozMovementX.");
         ok(hasMovementY, "Mouse Event should have mozMovementY.");
+        ok(!gotContextMenuEvent, "Shouldn't have got a contextmenu event.");
       }
 
       function mouseMoveHandler(e) {
         document.removeEventListener("mousemove", mouseMoveHandler, false);
 
         hasMovementX = "mozMovementX" in e;
         hasMovementY = "mozMovementY" in e;
 
@@ -57,16 +59,24 @@
       }
 
       document.addEventListener("mozpointerlockchange", function (e) {
         pointerLockChangeEventFired = true;
 
         if (document.mozPointerLockElement) {
           pointerLocked = true;
           pointerLockElement = document.mozPointerLockElement === div;
+ 
+          window.addEventListener("contextmenu",
+                                  function() { gotContextMenuEvent = true; },
+                                  true);
+          synthesizeMouse(document.body, 4, 4,
+                          { type: "contextmenu", button: 2 },
+                          window);
+
           document.addEventListener("mousemove", mouseMoveHandler, false);
           synthesizeMouseAtCenter(div, {type: "mousemove"}, window);
         } else {
           pointerUnlocked = true;
           document.mozCancelFullScreen();
         }
       }, false);
 
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -183,8 +183,9 @@ skip-if = (os == "win") || (os == "mac")
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 982828
 [test_websocket.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 982828
 [test_websocket_loadgroup.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 982828
 [test_bug1062920.html]
 [test_webSocket_sharedWorker.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 982828
+[test_websocket_pref.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_websocket_pref.html
@@ -0,0 +1,73 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for WebSocket object in workers</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<script id="js_script" type="text/js-worker">
+onmessage = function() {
+  postMessage("WebSocket" in this ? "OK" : "KO");
+}
+</script>
+
+<script class="testbody" type="text/javascript">
+
+  var blob = new Blob([document.getElementById("js_script").textContent],
+                      {type: "text/javascript"});
+  var url = URL.createObjectURL(blob);
+
+  var tests = [
+    function() {
+      SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", true]]},
+      function() {
+        ok("WebSocket" in window, "WebSocket are always enabled on main-thread");
+
+        var w = new Worker(url);
+        w.onmessage = function(e) {
+          is(e.data, "OK", "WebSocket enabled in workers!");
+          runTest();
+        }
+        w.postMessage('go');
+      });
+    },
+
+    function() {
+      SpecialPowers.pushPrefEnv({"set": [["dom.workers.websocket.enabled", false]]},
+      function() {
+        ok("WebSocket" in window, "WebSocket are always enabled on main-thread");
+
+        var w = new Worker(url);
+        w.onmessage = function(e) {
+          is(e.data, "KO", "WebSocket disabled in workers!");
+          runTest();
+        }
+        w.postMessage('go');
+      });
+    }
+  ];
+
+  function runTest() {
+    if (!tests.length) {
+      SimpleTest.finish();
+      return;
+    }
+
+    var t = tests.shift();
+    t();
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  runTest();
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -913,33 +913,33 @@ HasLookupRuleWithGlyphByScript(hb_face_t
 
     // look for the glyph among default feature lookups
     aHasDefaultFeatureWithGlyph = false;
     hb_set_t *glyphs = hb_set_create();
     hb_codepoint_t index = -1;
     while (hb_set_next(defaultFeatureLookups, &index)) {
         hb_ot_layout_lookup_collect_glyphs(aFace, aTableTag, index,
                                            glyphs, glyphs, glyphs,
-                                           glyphs);
+                                           nullptr);
         if (hb_set_has(glyphs, aGlyph)) {
             aHasDefaultFeatureWithGlyph = true;
             break;
         }
     }
 
     // look for the glyph among non-default feature lookups
     // if no default feature lookups contained spaces
     bool hasNonDefaultFeatureWithGlyph = false;
     if (!aHasDefaultFeatureWithGlyph) {
         hb_set_clear(glyphs);
         index = -1;
         while (hb_set_next(nonDefaultFeatureLookups, &index)) {
             hb_ot_layout_lookup_collect_glyphs(aFace, aTableTag, index,
                                                glyphs, glyphs, glyphs,
-                                               glyphs);
+                                               nullptr);
             if (hb_set_has(glyphs, aGlyph)) {
                 hasNonDefaultFeatureWithGlyph = true;
                 break;
             }
         }
     }
 
     hb_set_destroy(glyphs);
@@ -983,30 +983,30 @@ HasLookupRuleWithGlyph(hb_face_t *aFace,
     }
 
     // look for the glyph among non-specific feature lookups
     hb_set_t *glyphs = hb_set_create();
     hb_codepoint_t index = -1;
     while (hb_set_next(otherLookups, &index)) {
         hb_ot_layout_lookup_collect_glyphs(aFace, aTableTag, index,
                                            glyphs, glyphs, glyphs,
-                                           glyphs);
+                                           nullptr);
         if (hb_set_has(glyphs, aGlyph)) {
             aHasGlyph = true;
             break;
         }
     }
 
     // look for the glyph among specific feature lookups
     hb_set_clear(glyphs);
     index = -1;
     while (hb_set_next(specificFeatureLookups, &index)) {
         hb_ot_layout_lookup_collect_glyphs(aFace, aTableTag, index,
                                            glyphs, glyphs, glyphs,
-                                           glyphs);
+                                           nullptr);
         if (hb_set_has(glyphs, aGlyph)) {
             aHasGlyphSpecific = true;
             break;
         }
     }
 
     hb_set_destroy(glyphs);
     hb_set_destroy(specificFeatureLookups);
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -2232,40 +2232,43 @@ js::LookupAsmJSModuleInCache(ExclusiveCo
     ModuleCharsForLookup moduleChars;
     cursor = moduleChars.deserialize(cx, cursor);
     if (!moduleChars.match(parser))
         return true;
 
     uint32_t srcStart = parser.pc->maybeFunction->pn_body->pn_pos.begin;
     uint32_t srcBodyStart = parser.tokenStream.currentToken().pos.end;
     bool strict = parser.pc->sc->strict && !parser.pc->sc->hasExplicitUseStrict();
+
     // usesSignalHandlers will be clobbered when deserializing
     ScopedJSDeletePtr<AsmJSModule> module(
         cx->new_<AsmJSModule>(parser.ss, srcStart, srcBodyStart, strict,
                               /* usesSignalHandlers = */ false));
     if (!module)
         return false;
+
     cursor = module->deserialize(cx, cursor);
-
-    // No need to flush the instruction cache now, it will be flushed when dynamically linking.
-    AutoFlushICache afc("LookupAsmJSModuleInCache", /* inhibit= */ true);
-    // We already know the exact extent of areas that need to be patched, just make sure we
-    // flush all of them at once.
-    module->setAutoFlushICacheRange();
-
     if (!cursor)
         return false;
 
     bool atEnd = cursor == entry.memory + entry.serializedSize;
     MOZ_ASSERT(atEnd, "Corrupt cache file");
     if (!atEnd)
         return true;
 
-    module->staticallyLink(cx);
+    parser.tokenStream.advance(module->srcEndBeforeCurly());
 
-    parser.tokenStream.advance(module->srcEndBeforeCurly());
+    {
+        // No need to flush the instruction cache now, it will be flushed when
+        // dynamically linking. We already know the exact extent of areas that need
+        // to be patched, just make sure we flush all of them at once.
+        AutoFlushICache afc("LookupAsmJSModuleInCache", /* inhibit= */ true);
+        module->setAutoFlushICacheRange();
+
+        module->staticallyLink(cx);
+    }
 
     int64_t usecAfter = PRMJ_Now();
     int ms = (usecAfter - usecBefore) / PRMJ_USEC_PER_MSEC;
     *compilationTimeReport = JS_smprintf("loaded from cache in %dms", ms);
     *moduleOut = module.forget();
     return true;
 }
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -2702,31 +2702,31 @@ class FunctionCompiler
             return;
         curBlock_->setSlot(info().localSlot(local.slot), def);
     }
 
     MDefinition *loadHeap(Scalar::Type vt, MDefinition *ptr, NeedsBoundsCheck chk)
     {
         if (inDeadCode())
             return nullptr;
-        MAsmJSLoadHeap *load = MAsmJSLoadHeap::New(alloc(), vt, ptr);
+
+        bool needsBoundsCheck = chk == NEEDS_BOUNDS_CHECK && !m().usesSignalHandlersForOOB();
+        MAsmJSLoadHeap *load = MAsmJSLoadHeap::New(alloc(), vt, ptr, needsBoundsCheck);
         curBlock_->add(load);
-        if (chk == NO_BOUNDS_CHECK || m().usesSignalHandlersForOOB())
-            load->setSkipBoundsCheck(true);
         return load;
     }
 
     void storeHeap(Scalar::Type vt, MDefinition *ptr, MDefinition *v, NeedsBoundsCheck chk)
     {
         if (inDeadCode())
             return;
-        MAsmJSStoreHeap *store = MAsmJSStoreHeap::New(alloc(), vt, ptr, v);
+
+        bool needsBoundsCheck = chk == NEEDS_BOUNDS_CHECK && !m().usesSignalHandlersForOOB();
+        MAsmJSStoreHeap *store = MAsmJSStoreHeap::New(alloc(), vt, ptr, v, needsBoundsCheck);
         curBlock_->add(store);
-        if (chk == NO_BOUNDS_CHECK || m().usesSignalHandlersForOOB())
-            store->setSkipBoundsCheck(true);
     }
 
     MDefinition *loadGlobalVar(const ModuleCompiler::Global &global)
     {
         if (inDeadCode())
             return nullptr;
 
         MIRType type = global.varOrConstType().toMIRType();
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1631,18 +1631,17 @@ OutlineTypedObject::createUnattachedWith
 
 void
 OutlineTypedObject::attach(JSContext *cx, ArrayBufferObject &buffer, int32_t offset)
 {
     MOZ_ASSERT(!isAttached());
     MOZ_ASSERT(offset >= 0);
     MOZ_ASSERT((size_t) (offset + size()) <= buffer.byteLength());
 
-    if (typeDescr().is<SizedTypeDescr>())
-        buffer.setHasSizedObjectViews();
+    buffer.setHasTypedObjectViews();
 
     if (!buffer.addView(cx, this))
         CrashAtUnhandlableOOM("TypedObject::attach");
 
     setOwnerAndData(&buffer, buffer.dataPointer() + offset);
 }
 
 void
@@ -2434,17 +2433,17 @@ InlineTransparentTypedObject::getOrCreat
     // The owning object must always be the array buffer's first view. This
     // both prevents the memory from disappearing out from under the buffer
     // (the first view is held strongly by the buffer) and is used by the
     // buffer marking code to detect whether its data pointer needs to be
     // relocated.
     JS_ALWAYS_TRUE(buffer->addView(cx, this));
 
     buffer->setForInlineTypedObject();
-    buffer->setHasSizedObjectViews();
+    buffer->setHasTypedObjectViews();
 
     if (!table->addBuffer(cx, this, buffer))
         return nullptr;
 
     return buffer;
 }
 
 ArrayBufferObject *
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -278,28 +278,25 @@ Fold(ExclusiveContext *cx, ParseNode **p
     ParseNode *pn = *pnp;
     ParseNode *pn1 = nullptr, *pn2 = nullptr, *pn3 = nullptr;
 
     JS_CHECK_RECURSION(cx, return false);
 
     // First, recursively fold constants on the children of this node.
     switch (pn->getArity()) {
       case PN_CODE:
-        if (pn->isKind(PNK_FUNCTION) &&
-            pn->pn_funbox->useAsmOrInsideUseAsm() && options.asmJSOption)
-        {
+        if (pn->isKind(PNK_FUNCTION) && pn->pn_funbox->useAsmOrInsideUseAsm())
             return true;
-        } else {
-            // Note: pn_body is nullptr for functions which are being lazily parsed.
-            MOZ_ASSERT(pn->getKind() == PNK_FUNCTION);
-            if (pn->pn_body) {
-                if (!Fold(cx, &pn->pn_body, handler, options, pn->pn_funbox->inGenexpLambda,
-                          SyntacticContext::Other))
-                    return false;
-            }
+
+        // Note: pn_body is nullptr for functions which are being lazily parsed.
+        MOZ_ASSERT(pn->getKind() == PNK_FUNCTION);
+        if (pn->pn_body) {
+            if (!Fold(cx, &pn->pn_body, handler, options, pn->pn_funbox->inGenexpLambda,
+                      SyntacticContext::Other))
+                return false;
         }
         break;
 
       case PN_LIST:
       {
         // Propagate Condition context through logical connectives.
         SyntacticContext kidsc = SyntacticContext::Other;
         if (pn->isKind(PNK_OR) || pn->isKind(PNK_AND))
@@ -880,13 +877,13 @@ Fold(ExclusiveContext *cx, ParseNode **p
 
 bool
 frontend::FoldConstants(ExclusiveContext *cx, ParseNode **pnp, Parser<FullParseHandler> *parser)
 {
     // Don't fold constants if the code has requested "use asm" as
     // constant-folding will misrepresent the source text for the purpose
     // of type checking. (Also guard against entering a function containing
     // "use asm", see PN_FUNC case below.)
-    if (parser->pc->useAsmOrInsideUseAsm() && parser->options().asmJSOption)
+    if (parser->pc->useAsmOrInsideUseAsm())
         return true;
 
     return Fold(cx, pnp, parser->handler, parser->options(), false, SyntacticContext::Other);
 }
--- a/js/src/jit-test/tests/asm.js/testHeapAccess.js
+++ b/js/src/jit-test/tests/asm.js/testHeapAccess.js
@@ -26,29 +26,35 @@ assertEq(f(0x100),0);
 
 // Test signal handlers deactivation
 (function() {
     var jco = getJitCompilerOptions();
     var signalHandlersBefore = jco["signals.enable"];
     if (signalHandlersBefore == 1) {
         setJitCompilerOption("signals.enable", 0);
 
+        var buf = new ArrayBuffer(BUF_MIN);
+
         if (isCachingEnabled()) {
             // Cloned modules should fail on linking if the initial module has
             // been compiled with signals but signals are deactivated.
             var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return i8[0]|0}; return f');
             assertAsmLinkFail(code, this, null, new ArrayBuffer(BUF_MIN));
         }
 
         var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + '/* not a clone */ function f(i) {i=i|0; i32[0] = i; return i8[0]|0}; return f');
-        var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
+        var f = asmLink(code, this, null, buf);
         assertEq(f(0),0);
         assertEq(f(0x7f),0x7f);
         assertEq(f(0xff),-1);
         assertEq(f(0x100),0);
+
+        // Bug 1088655
+        assertEq(asmLink(asmCompile('stdlib', 'foreign', 'heap', USE_ASM + 'var i32=new stdlib.Int32Array(heap); function f(i) {i=i|0;var j=0x10000;return (i32[j>>2] = i)|0 } return f'), this, null, buf)(1), 1);
+
         setJitCompilerOption("signals.enable", 1);
     }
     jco = getJitCompilerOptions();
     var signalHandlersAfter = jco["signals.enable"];
     assertEq(signalHandlersBefore, signalHandlersAfter);
 })();
 
 setCachingEnabled(false);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1090037.js
@@ -0,0 +1,7 @@
+function f(x) {
+    Math.sin([] | 0 && x)
+}
+for (var j = 0; j < 1; j++) {
+    f(1 && 0)
+}
+
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -7257,17 +7257,17 @@ IonBuilder::checkTypedObjectIndexInBound
     int32_t lenOfAll;
     MDefinition *length;
     if (objPrediction.hasKnownArrayLength(&lenOfAll)) {
         length = constantInt(lenOfAll);
 
         // If we are not loading the length from the object itself, only
         // optimize if the array buffer can't have been neutered.
         types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
-        if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED))
+        if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
             return false;
     } else if (objPrediction.kind() == type::UnsizedArray) {
         // Note: unsized arrays will have their length set to zero if they are
         // neutered, so we don't need to make sure that no neutering has
         // occurred which affects this object.
         length = MTypedObjectUnsizedLength::New(alloc(), obj);
         current->add(length->toInstruction());
     } else {
@@ -8558,30 +8558,55 @@ IonBuilder::jsop_length_fastPath()
         current->add(ins);
         current->push(ins);
         return true;
     }
 
     if (obj->mightBeType(MIRType_Object)) {
         types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
 
+        // Compute the length for array objects.
         if (objTypes &&
             objTypes->getKnownClass() == &ArrayObject::class_ &&
             !objTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_LENGTH_OVERFLOW))
         {
             current->pop();
             MElements *elements = MElements::New(alloc(), obj);
             current->add(elements);
 
             // Read length.
             MArrayLength *length = MArrayLength::New(alloc(), elements);
             current->add(length);
             current->push(length);
             return true;
         }
+
+        // Compute the length for array typed objects.
+        TypedObjectPrediction prediction = typedObjectPrediction(obj);
+        if (!prediction.isUseless()) {
+            types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
+            if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
+                return false;
+
+            MInstruction *length;
+            int32_t sizedLength;
+            if (prediction.hasKnownArrayLength(&sizedLength)) {
+                obj->setImplicitlyUsedUnchecked();
+                length = MConstant::New(alloc(), Int32Value(sizedLength));
+            } else if (prediction.kind() == type::UnsizedArray) {
+                length = MTypedObjectUnsizedLength::New(alloc(), obj);
+            } else {
+                return false;
+            }
+
+            current->pop();
+            current->add(length);
+            current->push(length);
+            return true;
+        }
     }
 
     return false;
 }
 
 bool
 IonBuilder::jsop_arguments()
 {
@@ -9303,34 +9328,34 @@ IonBuilder::getPropTryScalarPropOfTypedO
                                               TypedObjectPrediction fieldPrediction,
                                               types::TemporaryTypeSet *resultTypes)
 {
     // Must always be loading the same scalar type
     Scalar::Type fieldType = fieldPrediction.scalarType();
 
     // Don't optimize if the typed object might be neutered.
     types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
-    if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED))
+    if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
         return true;
 
     // OK, perform the optimization.
     return pushScalarLoadFromTypedObject(emitted, typedObj, constantInt(fieldOffset), fieldType);
 }
 
 bool
 IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
                                                MDefinition *typedObj,
                                                int32_t fieldOffset,
                                                TypedObjectPrediction fieldPrediction,
                                                size_t fieldIndex,
                                                types::TemporaryTypeSet *resultTypes)
 {
     // Don't optimize if the typed object might be neutered.
     types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
-    if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED))
+    if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
         return true;
 
     // OK, perform the optimization
 
     // Identify the type object for the field.
     MDefinition *type = loadTypedObjectType(typedObj);
     MDefinition *fieldTypeObj = typeObjectForFieldFromStructType(type, fieldIndex);
 
@@ -9979,17 +10004,17 @@ IonBuilder::setPropTryScalarPropOfTypedO
                                               MDefinition *value,
                                               TypedObjectPrediction fieldPrediction)
 {
     // Must always be loading the same scalar type
     Scalar::Type fieldType = fieldPrediction.scalarType();
 
     // Don't optimize if the typed object might be neutered.
     types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
-    if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED))
+    if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
         return true;
 
     // OK! Perform the optimization.
 
     if (!storeScalarTypedObjectValue(obj, constantInt(fieldOffset), fieldType, false, value))
         return false;
 
     current->push(value);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1296,16 +1296,33 @@ MPhi::foldsTernary()
     if (!trueDef->isConstant() && !falseDef->isConstant())
         return nullptr;
 
     MConstant *c = trueDef->isConstant() ? trueDef->toConstant() : falseDef->toConstant();
     MDefinition *testArg = (trueDef == c) ? falseDef : trueDef;
     if (testArg != test->input())
         return nullptr;
 
+    // This check should be a tautology, except that the constant might be the
+    // result of the removal of a branch.  In such case the domination scope of
+    // the block which is holding the constant might be incomplete. This
+    // condition is used to prevent doing this optimization based on incomplete
+    // information.
+    //
+    // As GVN removed a branch, it will update the dominations rules before
+    // trying to fold this MPhi again. Thus, this condition does not inhibit
+    // this optimization.
+    MBasicBlock *truePred = block()->getPredecessor(firstIsTrueBranch ? 0 : 1);
+    MBasicBlock *falsePred = block()->getPredecessor(firstIsTrueBranch ? 1 : 0);
+    if (!trueDef->block()->dominates(truePred) ||
+        !falseDef->block()->dominates(falsePred))
+    {
+        return nullptr;
+    }
+
     // If testArg is an int32 type we can:
     // - fold testArg ? testArg : 0 to testArg
     // - fold testArg ? 0 : testArg to 0
     if (testArg->type() == MIRType_Int32 && c->vp()->toNumber() == 0) {
         // When folding to the constant we need to hoist it.
         if (trueDef == c && !c->block()->dominates(block()))
             c->block()->moveBefore(pred->lastIns(), c);
         return trueDef;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -11649,71 +11649,73 @@ class MAsmJSNeg : public MUnaryInstructi
     static MAsmJSNeg *NewAsmJS(TempAllocator &alloc, MDefinition *op, MIRType type) {
         return new(alloc) MAsmJSNeg(op, type);
     }
 };
 
 class MAsmJSHeapAccess
 {
     Scalar::Type viewType_;
-    bool skipBoundsCheck_;
-
-  public:
-    explicit MAsmJSHeapAccess(Scalar::Type vt)
-      : viewType_(vt), skipBoundsCheck_(false)
+    bool needsBoundsCheck_;
+
+  public:
+    MAsmJSHeapAccess(Scalar::Type vt, bool needsBoundsCheck)
+      : viewType_(vt), needsBoundsCheck_(needsBoundsCheck)
     {}
 
     Scalar::Type viewType() const { return viewType_; }
-    bool skipBoundsCheck() const { return skipBoundsCheck_; }
-    void setSkipBoundsCheck(bool v) { skipBoundsCheck_ = v; }
+    bool needsBoundsCheck() const { return needsBoundsCheck_; }
+    void removeBoundsCheck() { needsBoundsCheck_ = false; }
 };
 
 class MAsmJSLoadHeap : public MUnaryInstruction, public MAsmJSHeapAccess
 {
-    MAsmJSLoadHeap(Scalar::Type vt, MDefinition *ptr)
-      : MUnaryInstruction(ptr), MAsmJSHeapAccess(vt)
+    MAsmJSLoadHeap(Scalar::Type vt, MDefinition *ptr, bool needsBoundsCheck)
+      : MUnaryInstruction(ptr), MAsmJSHeapAccess(vt, needsBoundsCheck)
     {
         setMovable();
         if (vt == Scalar::Float32)
             setResultType(MIRType_Float32);
         else if (vt == Scalar::Float64)
             setResultType(MIRType_Double);
         else
             setResultType(MIRType_Int32);
     }
 
   public:
     INSTRUCTION_HEADER(AsmJSLoadHeap);
 
-    static MAsmJSLoadHeap *New(TempAllocator &alloc, Scalar::Type vt, MDefinition *ptr) {
-        return new(alloc) MAsmJSLoadHeap(vt, ptr);
+    static MAsmJSLoadHeap *New(TempAllocator &alloc, Scalar::Type vt,
+                               MDefinition *ptr, bool needsBoundsCheck)
+    {
+        return new(alloc) MAsmJSLoadHeap(vt, ptr, needsBoundsCheck);
     }
 
     MDefinition *ptr() const { return getOperand(0); }
 
     bool congruentTo(const MDefinition *ins) const;
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::AsmJSHeap);
     }
     bool mightAlias(const MDefinition *def) const;
 };
 
 class MAsmJSStoreHeap : public MBinaryInstruction, public MAsmJSHeapAccess
 {
-    MAsmJSStoreHeap(Scalar::Type vt, MDefinition *ptr, MDefinition *v)
-      : MBinaryInstruction(ptr, v) , MAsmJSHeapAccess(vt)
+    MAsmJSStoreHeap(Scalar::Type vt, MDefinition *ptr, MDefinition *v, bool needsBoundsCheck)
+      : MBinaryInstruction(ptr, v) , MAsmJSHeapAccess(vt, needsBoundsCheck)
     {}
 
   public:
     INSTRUCTION_HEADER(AsmJSStoreHeap);
 
     static MAsmJSStoreHeap *New(TempAllocator &alloc, Scalar::Type vt,
-                                MDefinition *ptr, MDefinition *v)
-    {
-        return new(alloc) MAsmJSStoreHeap(vt, ptr, v);
+                                MDefinition *ptr, MDefinition *v, bool needsBoundsCheck)
+    {
+        return new(alloc) MAsmJSStoreHeap(vt, ptr, v, needsBoundsCheck);
     }
 
     MDefinition *ptr() const { return getOperand(0); }
     MDefinition *value() const { return getOperand(1); }
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::AsmJSHeap);
     }
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -2020,24 +2020,24 @@ RangeAnalysis::analyze()
             // methods but it needs the minAsmJSHeapLength().
             if (mir->compilingAsmJS()) {
                 uint32_t minHeapLength = mir->minAsmJSHeapLength();
                 if (iter->isAsmJSLoadHeap()) {
                     MAsmJSLoadHeap *ins = iter->toAsmJSLoadHeap();
                     Range *range = ins->ptr()->range();
                     if (range && range->hasInt32LowerBound() && range->lower() >= 0 &&
                         range->hasInt32UpperBound() && (uint32_t) range->upper() < minHeapLength) {
-                        ins->setSkipBoundsCheck(true);
+                        ins->removeBoundsCheck();
                     }
                 } else if (iter->isAsmJSStoreHeap()) {
                     MAsmJSStoreHeap *ins = iter->toAsmJSStoreHeap();
                     Range *range = ins->ptr()->range();
                     if (range && range->hasInt32LowerBound() && range->lower() >= 0 &&
                         range->hasInt32UpperBound() && (uint32_t) range->upper() < minHeapLength) {
-                        ins->setSkipBoundsCheck(true);
+                        ins->removeBoundsCheck();
                     }
                 }
             }
         }
     }
 
     return true;
 }
--- a/js/src/jit/ValueNumbering.cpp
+++ b/js/src/jit/ValueNumbering.cpp
@@ -649,16 +649,20 @@ ValueNumberer::leader(MDefinition *def)
             // The congruent value doesn't dominate. It never will again in this
             // dominator tree, so overwrite it.
             values_.overwrite(p, def);
         } else {
             // No match. Add a new entry.
             if (!values_.add(p, def))
                 return nullptr;
         }
+
+#ifdef DEBUG
+        JitSpew(JitSpew_GVN, "      Recording %s%u", def->opName(), def->id());
+#endif
     }
 
     return def;
 }
 
 // Test whether |phi| is dominated by a congruent phi.
 bool
 ValueNumberer::hasLeader(const MPhi *phi, const MBasicBlock *phiBlock) const
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -1887,17 +1887,17 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAs
       case Scalar::Float64: isFloat = true;   size = 64; break;
       case Scalar::Float32: isFloat = true;   size = 32; break;
       default: MOZ_CRASH("unexpected array type");
     }
 
     const LAllocation *ptr = ins->ptr();
 
     if (ptr->isConstant()) {
-        MOZ_ASSERT(mir->skipBoundsCheck());
+        MOZ_ASSERT(!mir->needsBoundsCheck());
         int32_t ptrImm = ptr->toConstant()->toInt32();
         MOZ_ASSERT(ptrImm >= 0);
         if (isFloat) {
             VFPRegister vd(ToFloatRegister(ins->output()));
             if (size == 32)
                 masm.ma_vldr(Operand(HeapReg, ptrImm), vd.singleOverlay(), Assembler::Always);
             else
                 masm.ma_vldr(Operand(HeapReg, ptrImm), vd, Assembler::Always);
@@ -1905,17 +1905,17 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAs
             masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, Imm32(ptrImm),
                                   ToRegister(ins->output()), Offset, Assembler::Always);
         }
         return true;
     }
 
     Register ptrReg = ToRegister(ptr);
 
-    if (mir->skipBoundsCheck()) {
+    if (!mir->needsBoundsCheck()) {
         if (isFloat) {
             VFPRegister vd(ToFloatRegister(ins->output()));
             if (size == 32)
                 masm.ma_vldr(vd.singleOverlay(), HeapReg, ptrReg, 0, Assembler::Always);
             else
                 masm.ma_vldr(vd, HeapReg, ptrReg, 0, Assembler::Always);
         } else {
             masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, ptrReg,
@@ -1961,17 +1961,17 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LA
       case Scalar::Int32:
       case Scalar::Uint32:  isSigned = true;  size = 32; break;
       case Scalar::Float64: isFloat  = true;  size = 64; break;
       case Scalar::Float32: isFloat = true;   size = 32; break;
       default: MOZ_CRASH("unexpected array type");
     }
     const LAllocation *ptr = ins->ptr();
     if (ptr->isConstant()) {
-        MOZ_ASSERT(mir->skipBoundsCheck());
+        MOZ_ASSERT(!mir->needsBoundsCheck());
         int32_t ptrImm = ptr->toConstant()->toInt32();
         MOZ_ASSERT(ptrImm >= 0);
         if (isFloat) {
             VFPRegister vd(ToFloatRegister(ins->value()));
             if (size == 32)
                 masm.ma_vstr(vd.singleOverlay(), Operand(HeapReg, ptrImm), Assembler::Always);
             else
                 masm.ma_vstr(vd, Operand(HeapReg, ptrImm), Assembler::Always);
@@ -1979,17 +1979,17 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LA
             masm.ma_dataTransferN(IsStore, size, isSigned, HeapReg, Imm32(ptrImm),
                                   ToRegister(ins->value()), Offset, Assembler::Always);
         }
         return true;
     }
 
     Register ptrReg = ToRegister(ptr);
 
-    if (mir->skipBoundsCheck()) {
+    if (!mir->needsBoundsCheck()) {
         Register ptrReg = ToRegister(ptr);
         if (isFloat) {
             VFPRegister vd(ToFloatRegister(ins->value()));
             if (size == 32)
                 masm.ma_vstr(vd.singleOverlay(), HeapReg, ptrReg, 0, Assembler::Always);
             else
                 masm.ma_vstr(vd, HeapReg, ptrReg, 0, Assembler::Always);
         } else {
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -484,17 +484,17 @@ LIRGeneratorARM::visitAsmJSUnsignedToFlo
 bool
 LIRGeneratorARM::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
 {
     MDefinition *ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
     LAllocation ptrAlloc;
 
     // For the ARM it is best to keep the 'ptr' in a register if a bounds check is needed.
-    if (ptr->isConstant() && ins->skipBoundsCheck()) {
+    if (ptr->isConstant() && !ins->needsBoundsCheck()) {
         int32_t ptrValue = ptr->toConstant()->value().toInt32();
         // A bounds check is only skipped for a positive index.
         MOZ_ASSERT(ptrValue >= 0);
         ptrAlloc = LAllocation(ptr->toConstant()->vp());
     } else
         ptrAlloc = useRegisterAtStart(ptr);
 
     return define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins);
@@ -502,17 +502,17 @@ LIRGeneratorARM::visitAsmJSLoadHeap(MAsm
 
 bool
 LIRGeneratorARM::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
 {
     MDefinition *ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
     LAllocation ptrAlloc;
 
-    if (ptr->isConstant() && ins->skipBoundsCheck()) {
+    if (ptr->isConstant() && !ins->needsBoundsCheck()) {
         MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0);
         ptrAlloc = LAllocation(ptr->toConstant()->vp());
     } else
         ptrAlloc = useRegisterAtStart(ptr);
 
     return add(new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())), ins);
 }
 
--- a/js/src/jit/mips/CodeGenerator-mips.cpp
+++ b/js/src/jit/mips/CodeGenerator-mips.cpp
@@ -1962,17 +1962,17 @@ CodeGeneratorMIPS::visitAsmJSLoadHeap(LA
       case Scalar::Int32:   isSigned = true;  size = 32; break;
       case Scalar::Uint32:  isSigned = false; size = 32; break;
       case Scalar::Float64: isFloat  = true;  size = 64; break;
       case Scalar::Float32: isFloat  = true;  size = 32; break;
       default: MOZ_CRASH("unexpected array type");
     }
 
     if (ptr->isConstant()) {
-        MOZ_ASSERT(mir->skipBoundsCheck());
+        MOZ_ASSERT(!mir->needsBoundsCheck());
         int32_t ptrImm = ptr->toConstant()->toInt32();
         MOZ_ASSERT(ptrImm >= 0);
         if (isFloat) {
             if (size == 32) {
                 masm.loadFloat32(Address(HeapReg, ptrImm), ToFloatRegister(out));
             } else {
                 masm.loadDouble(Address(HeapReg, ptrImm), ToFloatRegister(out));
             }
@@ -1980,17 +1980,17 @@ CodeGeneratorMIPS::visitAsmJSLoadHeap(LA
             masm.ma_load(ToRegister(out), Address(HeapReg, ptrImm),
                          static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
         }
         return true;
     }
 
     Register ptrReg = ToRegister(ptr);
 
-    if (mir->skipBoundsCheck()) {
+    if (!mir->needsBoundsCheck()) {
         if (isFloat) {
             if (size == 32) {
                 masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
             } else {
                 masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
             }
         } else {
             masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne),
@@ -2051,17 +2051,17 @@ CodeGeneratorMIPS::visitAsmJSStoreHeap(L
       case Scalar::Int32:   isSigned = true;  size = 32; break;
       case Scalar::Uint32:  isSigned = false; size = 32; break;
       case Scalar::Float64: isFloat  = true;  size = 64; break;
       case Scalar::Float32: isFloat  = true;  size = 32; break;
       default: MOZ_CRASH("unexpected array type");
     }
 
     if (ptr->isConstant()) {
-        MOZ_ASSERT(mir->skipBoundsCheck());
+        MOZ_ASSERT(!mir->needsBoundsCheck());
         int32_t ptrImm = ptr->toConstant()->toInt32();
         MOZ_ASSERT(ptrImm >= 0);
 
         if (isFloat) {
             if (size == 32) {
                 masm.storeFloat32(ToFloatRegister(value), Address(HeapReg, ptrImm));
             } else {
                 masm.storeDouble(ToFloatRegister(value), Address(HeapReg, ptrImm));
@@ -2071,17 +2071,17 @@ CodeGeneratorMIPS::visitAsmJSStoreHeap(L
                           static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
         }
         return true;
     }
 
     Register ptrReg = ToRegister(ptr);
     Address dstAddr(ptrReg, 0);
 
-    if (mir->skipBoundsCheck()) {
+    if (!mir->needsBoundsCheck()) {
         if (isFloat) {
             if (size == 32) {
                 masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
             } else
                 masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
         } else {
             masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne),
                           static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
--- a/js/src/jit/mips/Lowering-mips.cpp
+++ b/js/src/jit/mips/Lowering-mips.cpp
@@ -463,17 +463,17 @@ bool
 LIRGeneratorMIPS::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
 {
     MDefinition *ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
     LAllocation ptrAlloc;
 
     // For MIPS it is best to keep the 'ptr' in a register if a bounds check
     // is needed.
-    if (ptr->isConstant() && ins->skipBoundsCheck()) {
+    if (ptr->isConstant() && !ins->needsBoundsCheck()) {
         int32_t ptrValue = ptr->toConstant()->value().toInt32();
         // A bounds check is only skipped for a positive index.
         MOZ_ASSERT(ptrValue >= 0);
         ptrAlloc = LAllocation(ptr->toConstant()->vp());
     } else
         ptrAlloc = useRegisterAtStart(ptr);
 
     return define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins);
@@ -481,17 +481,17 @@ LIRGeneratorMIPS::visitAsmJSLoadHeap(MAs
 
 bool
 LIRGeneratorMIPS::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
 {
     MDefinition *ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
     LAllocation ptrAlloc;
 
-    if (ptr->isConstant() && ins->skipBoundsCheck()) {
+    if (ptr->isConstant() && !ins->needsBoundsCheck()) {
         MOZ_ASSERT(ptr->toConstant()->value().toInt32() >= 0);
         ptrAlloc = LAllocation(ptr->toConstant()->vp());
     } else
         ptrAlloc = useRegisterAtStart(ptr);
 
     return add(new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterAtStart(ins->value())), ins);
 }
 
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -272,17 +272,17 @@ CodeGeneratorX64::visitAsmJSLoadHeap(LAs
         MOZ_ASSERT(ptrImm >= 0);
         srcAddr = Operand(HeapReg, ptrImm);
     } else {
         srcAddr = Operand(HeapReg, ToRegister(ptr), TimesOne);
     }
 
     OutOfLineLoadTypedArrayOutOfBounds *ool = nullptr;
     uint32_t maybeCmpOffset = AsmJSHeapAccess::NoLengthCheck;
-    if (!mir->skipBoundsCheck()) {
+    if (mir->needsBoundsCheck()) {
         bool isFloat32Load = vt == Scalar::Float32;
         ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out), isFloat32Load);
         if (!addOutOfLineCode(ool, ins->mir()))
             return false;
 
         CodeOffsetLabel cmp = masm.cmplWithPatch(ToRegister(ptr), Imm32(0));
         masm.j(Assembler::AboveOrEqual, ool->entry());
         maybeCmpOffset = cmp.offset();
@@ -320,17 +320,17 @@ CodeGeneratorX64::visitAsmJSStoreHeap(LA
         MOZ_ASSERT(ptrImm >= 0);
         dstAddr = Operand(HeapReg, ptrImm);
     } else {
         dstAddr = Operand(HeapReg, ToRegister(ptr), TimesOne);
     }
 
     Label rejoin;
     uint32_t maybeCmpOffset = AsmJSHeapAccess::NoLengthCheck;
-    if (!mir->skipBoundsCheck()) {
+    if (mir->needsBoundsCheck()) {
         CodeOffsetLabel cmp = masm.cmplWithPatch(ToRegister(ptr), Imm32(0));
         masm.j(Assembler::AboveOrEqual, &rejoin);
         maybeCmpOffset = cmp.offset();
     }
 
     uint32_t before = masm.size();
     if (ins->value()->isConstant()) {
         switch (vt) {
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -128,46 +128,45 @@ LIRGeneratorX64::visitAsmJSUnsignedToFlo
     return define(lir, ins);
 }
 
 bool
 LIRGeneratorX64::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
 {
     MDefinition *ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
-    LAllocation ptrAlloc;
 
-    bool useConstant = false;
-    if (ptr->isConstant()) {
-        int32_t ptrValue = ptr->toConstant()->value().toInt32();
-        if (ins->skipBoundsCheck() && ptrValue >= 0) {
-            // Only a positive index is accepted because a negative offset
-            // encoded as an offset in the addressing mode would not wrap back
-            // into the protected area reserved for the heap.
-            useConstant = true;
-        }
-        // In other cases, still keep the pointer in a register.
-    }
+    // Only a positive index is accepted because a negative offset encoded as an
+    // offset in the addressing mode would not wrap back into the protected area
+    // reserved for the heap. For simplicity (and since we don't care about
+    // getting maximum performance in these cases) only allow constant
+    // opererands when skipping bounds checks.
+    LAllocation ptrAlloc = ins->needsBoundsCheck()
+                           ? useRegisterAtStart(ptr)
+                           : useRegisterOrNonNegativeConstantAtStart(ptr);
 
-    ptrAlloc = (useConstant) ? LAllocation(ptr->toConstant()->vp()) : useRegisterAtStart(ptr);
-    LAsmJSLoadHeap *lir = new(alloc()) LAsmJSLoadHeap(ptrAlloc);
-    return define(lir, ins);
+    return define(new(alloc()) LAsmJSLoadHeap(ptrAlloc), ins);
 }
 
 bool
 LIRGeneratorX64::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
 {
     MDefinition *ptr = ins->ptr();
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
-    LAsmJSStoreHeap *lir;
 
-    // Note only a positive constant index is accepted because a negative offset
-    // encoded as an offset in the addressing mode would not wrap back into the
-    // protected area reserved for the heap.
-    LAllocation ptrAlloc = useRegisterOrNonNegativeConstantAtStart(ptr);
+    // Only a positive index is accepted because a negative offset encoded as an
+    // offset in the addressing mode would not wrap back into the protected area
+    // reserved for the heap. For simplicity (and since we don't care about
+    // getting maximum performance in these cases) only allow constant
+    // opererands when skipping bounds checks.
+    LAllocation ptrAlloc = ins->needsBoundsCheck()
+                           ? useRegisterAtStart(ptr)
+                           : useRegisterOrNonNegativeConstantAtStart(ptr);
+
+    LAsmJSStoreHeap *lir;
     switch (ins->viewType()) {
       case Scalar::Int8:
       case Scalar::Uint8:
       case Scalar::Int16:
       case Scalar::Uint16:
       case Scalar::Int32:
       case Scalar::Uint32:
         lir = new(alloc()) LAsmJSStoreHeap(ptrAlloc, useRegisterOrConstantAtStart(ins->value()));
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -373,17 +373,17 @@ CodeGeneratorX86::visitAsmJSLoadHeap(LAs
         // base address is known during dynamic linking (AsmJSModule::initHeap).
         PatchedAbsoluteAddress srcAddr((void *) ptr->toConstant()->toInt32());
         return loadAndNoteViewTypeElement(vt, srcAddr, out);
     }
 
     Register ptrReg = ToRegister(ptr);
     Address srcAddr(ptrReg, 0);
 
-    if (mir->skipBoundsCheck())
+    if (!mir->needsBoundsCheck())
         return loadAndNoteViewTypeElement(vt, srcAddr, out);
 
     bool isFloat32Load = vt == Scalar::Float32;
     OutOfLineLoadTypedArrayOutOfBounds *ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out), isFloat32Load);
     if (!addOutOfLineCode(ool, mir))
         return false;
 
     CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
@@ -462,17 +462,17 @@ CodeGeneratorX86::visitAsmJSStoreHeap(LA
         PatchedAbsoluteAddress dstAddr((void *) ptr->toConstant()->toInt32());
         storeAndNoteViewTypeElement(vt, value, dstAddr);
         return true;
     }
 
     Register ptrReg = ToRegister(ptr);
     Address dstAddr(ptrReg, 0);
 
-    if (mir->skipBoundsCheck()) {
+    if (!mir->needsBoundsCheck()) {
         storeAndNoteViewTypeElement(vt, value, dstAddr);
         return true;
     }
 
     CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
     Label rejoin;
     masm.j(Assembler::AboveOrEqual, &rejoin);
 
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -214,17 +214,17 @@ LIRGeneratorX86::visitAsmJSUnsignedToFlo
 bool
 LIRGeneratorX86::visitAsmJSLoadHeap(MAsmJSLoadHeap *ins)
 {
     MDefinition *ptr = ins->ptr();
     LAllocation ptrAlloc;
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
 
     // For the x86 it is best to keep the 'ptr' in a register if a bounds check is needed.
-    if (ptr->isConstant() && ins->skipBoundsCheck()) {
+    if (ptr->isConstant() && !ins->needsBoundsCheck()) {
         int32_t ptrValue = ptr->toConstant()->value().toInt32();
         // A bounds check is only skipped for a positive index.
         MOZ_ASSERT(ptrValue >= 0);
         ptrAlloc = LAllocation(ptr->toConstant()->vp());
     } else {
         ptrAlloc = useRegisterAtStart(ptr);
     }
     LAsmJSLoadHeap *lir = new(alloc()) LAsmJSLoadHeap(ptrAlloc);
@@ -233,17 +233,17 @@ LIRGeneratorX86::visitAsmJSLoadHeap(MAsm
 
 bool
 LIRGeneratorX86::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
 {
     MDefinition *ptr = ins->ptr();
     LAsmJSStoreHeap *lir;
     MOZ_ASSERT(ptr->type() == MIRType_Int32);
 
-    if (ptr->isConstant() && ins->skipBoundsCheck()) {
+    if (ptr->isConstant() && !ins->needsBoundsCheck()) {
         int32_t ptrValue = ptr->toConstant()->value().toInt32();
         MOZ_ASSERT(ptrValue >= 0);
         LAllocation ptrAlloc = LAllocation(ptr->toConstant()->vp());
         switch (ins->viewType()) {
           case Scalar::Int8: case Scalar::Uint8:
             // See comment below.
             lir = new(alloc()) LAsmJSStoreHeap(ptrAlloc, useFixed(ins->value(), eax));
             break;
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -479,20 +479,19 @@ enum MOZ_ENUM_TYPE(uint32_t) {
     /*
      * For the function on a run-once script, whether the function has actually
      * run multiple times.
      */
     OBJECT_FLAG_RUNONCE_INVALIDATED   = 0x00200000,
 
     /*
      * For a global object, whether any array buffers in this compartment with
-     * sized typed object views have been neutered. Sized typed objects have
-     * different neutering checks from other array buffer views.
+     * typed object views have been neutered.
      */
-    OBJECT_FLAG_SIZED_OBJECT_NEUTERED = 0x00400000,
+    OBJECT_FLAG_TYPED_OBJECT_NEUTERED = 0x00400000,
 
     /*
      * Whether objects with this type should be allocated directly in the
      * tenured heap.
      */
     OBJECT_FLAG_PRE_TENURE            = 0x00800000,
 
     /* Whether objects with this type might have copy on write elements. */
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -510,31 +510,31 @@ ArrayBufferObject::neuterView(JSContext 
 /* static */ bool
 ArrayBufferObject::neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer,
                           BufferContents newContents)
 {
     if (buffer->isAsmJS() && !OnDetachAsmJSArrayBuffer(cx, buffer))
         return false;
 
     // When neutering buffers where we don't know all views, the new data must
-    // match the old data. All missing views are sized typed objects, which do
-    // not have a length property to mutate when neutering.
+    // match the old data. All missing views are typed objects, which do not
+    // expect their data to ever change.
     MOZ_ASSERT_IF(buffer->forInlineTypedObject(),
                   newContents.data() == buffer->dataPointer());
 
-    // When neutering a buffer with sized typed object views, any jitcode which
+    // When neutering a buffer with typed object views, any jitcode which
     // accesses such views needs to be deoptimized so that neuter checks are
     // performed. This is done by setting a compartment wide flag indicating
-    // that buffers with sized object views have been neutered.
-    if (buffer->hasSizedObjectViews()) {
+    // that buffers with typed object views have been neutered.
+    if (buffer->hasTypedObjectViews()) {
         // Make sure the global object's type has been instantiated, so the
         // flag change will be observed.
         if (!cx->global()->getType(cx))
             CrashAtUnhandlableOOM("ArrayBufferObject::neuter");
-        types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED);
+        types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED);
     }
 
     // Neuter all views on the buffer, clear out the list of views and the
     // buffer's data.
 
     if (InnerViewTable::ViewVector *views = cx->compartment()->innerViews.maybeViewsUnbarriered(buffer)) {
         for (size_t i = 0; i < views->length(); i++)
             buffer->neuterView(cx, (*views)[i], newContents);
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -135,21 +135,21 @@ class ArrayBufferObject : public ArrayBu
         // allocate their data inline, and buffers that are created lazily for
         // typed objects with inline storage, in which case the buffer points
         // directly to the typed object's storage.
         OWNS_DATA           = 0x8,
 
         // This array buffer was created lazily for a typed object with inline
         // data. This implies both that the typed object owns the buffer's data
         // and that the list of views sharing this buffer's data might be
-        // incomplete. Any missing views will be sized typed objects.
+        // incomplete. Any missing views will be typed objects.
         FOR_INLINE_TYPED_OBJECT = 0x10,
 
-        // Views of this buffer might include sized typed objects.
-        SIZED_OBJECT_VIEWS  = 0x20
+        // Views of this buffer might include typed objects.
+        TYPED_OBJECT_VIEWS  = 0x20
     };
 
   public:
 
     class BufferContents {
         uint8_t *data_;
         BufferKind kind_;
 
@@ -320,34 +320,34 @@ class ArrayBufferObject : public ArrayBu
         return getFixedSlotOffset(DATA_SLOT);
     }
 
     static uint32_t neuteredFlag() { return NEUTERED; }
 
     void setForInlineTypedObject() {
         setFlags(flags() | FOR_INLINE_TYPED_OBJECT);
     }
-    void setHasSizedObjectViews() {
-        setFlags(flags() | SIZED_OBJECT_VIEWS);
+    void setHasTypedObjectViews() {
+        setFlags(flags() | TYPED_OBJECT_VIEWS);
     }
 
   protected:
     void setDataPointer(BufferContents contents, OwnsState ownsState);
     void setByteLength(size_t length);
 
     uint32_t flags() const;
     void setFlags(uint32_t flags);
 
     bool ownsData() const { return flags() & OWNS_DATA; }
     void setOwnsData(OwnsState owns) {
         setFlags(owns ? (flags() | OWNS_DATA) : (flags() & ~OWNS_DATA));
     }
 
     bool forInlineTypedObject() const { return flags() & FOR_INLINE_TYPED_OBJECT; }
-    bool hasSizedObjectViews() const { return flags() & SIZED_OBJECT_VIEWS; }
+    bool hasTypedObjectViews() const { return flags() & TYPED_OBJECT_VIEWS; }
 
     void setIsAsmJSMalloced() { setFlags((flags() & ~KIND_MASK) | ASMJS_MALLOCED); }
     void setIsNeutered() { setFlags(flags() | NEUTERED); }
 
     void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
         setByteLength(byteLength);
         setFlags(0);
         setFirstView(nullptr);
--- a/layout/base/TouchCaret.cpp
+++ b/layout/base/TouchCaret.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 sw=2 et tw=78: */
 /* 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 "prlog.h"
 #include "TouchCaret.h"
 
 #include <algorithm>
 
 #include "nsCOMPtr.h"
 #include "nsFrameSelection.h"
 #include "nsIFrame.h"
 #include "nsIScrollableFrame.h"
@@ -29,26 +30,35 @@
 #include "nsView.h"
 #include "nsDOMTokenList.h"
 #include "nsCaret.h"
 #include "mozilla/dom/CustomEvent.h"
 #include "nsContentUtils.h"
 
 using namespace mozilla;
 
-// To enable all the TOUCHCARET_LOG print statements, change the 0 to 1 in the
-// following #define.
-#define ENABLE_TOUCHCARET_LOG 0
+#ifdef PR_LOGGING
+static PRLogModuleInfo* gTouchCaretLog;
+static const char* kTouchCaretLogModuleName = "TouchCaret";
 
-#if ENABLE_TOUCHCARET_LOG
-  #define TOUCHCARET_LOG(message, ...) \
-    printf_stderr("TouchCaret (%p): %s:%d : " message "\n", this, __func__, __LINE__, ##__VA_ARGS__);
+// To enable all the TOUCHCARET_LOG print statements, set the environment
+// variable NSPR_LOG_MODULES=TouchCaret:5
+#define TOUCHCARET_LOG(message, ...)                                           \
+  PR_LOG(gTouchCaretLog, PR_LOG_DEBUG,                                         \
+         ("TouchCaret (%p): %s:%d : " message "\n", this, __FUNCTION__,        \
+          __LINE__, ##__VA_ARGS__));
+
+#define TOUCHCARET_LOG_STATIC(message, ...)                                    \
+  PR_LOG(gTouchCaretLog, PR_LOG_DEBUG,                                         \
+         ("TouchCaret: %s:%d : " message "\n", __FUNCTION__, __LINE__,         \
+          ##__VA_ARGS__));
 #else
-  #define TOUCHCARET_LOG(message, ...)
-#endif
+#define TOUCHCARET_LOG(message, ...)
+#define TOUCHCARET_LOG_STATIC(message, ...)
+#endif // #ifdef PR_LOGGING
 
 // Click on the boundary of input/textarea will place the caret at the
 // front/end of the content. To advoid this, we need to deflate the content
 // boundary by 61 app units (1 pixel + 1 app unit).
 static const int32_t kBoundaryAppUnits = 61;
 
 NS_IMPL_ISUPPORTS(TouchCaret, nsISelectionListener)
 
@@ -57,18 +67,25 @@ NS_IMPL_ISUPPORTS(TouchCaret, nsISelecti
 
 TouchCaret::TouchCaret(nsIPresShell* aPresShell)
   : mState(TOUCHCARET_NONE),
     mActiveTouchId(-1),
     mCaretCenterToDownPointOffsetY(0),
     mVisible(false),
     mIsValidTap(false)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
+#ifdef PR_LOGGING
+  if (!gTouchCaretLog) {
+    gTouchCaretLog = PR_NewLogModule(kTouchCaretLogModuleName);
+  }
+#endif
+
   TOUCHCARET_LOG("Constructor, PresShell=%p", aPresShell);
-  MOZ_ASSERT(NS_IsMainThread());
 
   static bool addedTouchCaretPref = false;
   if (!addedTouchCaretPref) {
     Preferences::AddIntVarCache(&sTouchCaretInflateSize,
                                 "touchcaret.inflatesize.threshold");
     Preferences::AddIntVarCache(&sTouchCaretExpirationTime,
                                 "touchcaret.expiration.time");
     addedTouchCaretPref = true;
@@ -306,17 +323,17 @@ TouchCaret::IsOnTouchCaret(const nsPoint
   return mVisible && nsLayoutUtils::ContainsPoint(GetTouchFrameRect(), aPoint,
                                                   TouchCaretInflateSize());
 }
 
 nsresult
 TouchCaret::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection* aSel,
                                    int16_t aReason)
 {
-  TOUCHCARET_LOG("Reason=%d", aReason);
+  TOUCHCARET_LOG("aSel (%p), Reason=%d", aSel, aReason);
 
   // Hide touch caret while no caret exists.
   nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
   if (!presShell) {
     return NS_OK;
   }
 
   nsRefPtr<nsCaret> caret = presShell->GetCaret();
--- a/layout/reftests/scrolling/reftest.list
+++ b/layout/reftests/scrolling/reftest.list
@@ -11,16 +11,18 @@ random-if(Android&&!browserIsRemote) HTT
 skip-if(B2G) random-if(cocoaWidget) HTTP == opacity-mixed-scrolling-2.html opacity-mixed-scrolling-2.html?ref # see bug 625357
 skip-if(Android) pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-1.html scroll-behavior-1.html?ref # see bug 1041833
 skip-if(Android) pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-2.html scroll-behavior-2.html?ref # see bug 1041833
 skip-if(Android) pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-3.html scroll-behavior-3.html?ref # see bug 1041833
 skip-if(Android) pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-4.html scroll-behavior-4.html?ref # see bug 1041833
 skip-if(Android) pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-5.html scroll-behavior-5.html?ref # see bug 1041833
 skip-if(Android) pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-6.html scroll-behavior-6.html?ref # see bug 1041833
 skip-if(Android) pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-7.html scroll-behavior-7.html?ref # see bug 1041833
+skip-if(Android) pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-8.html scroll-behavior-8.html?ref # see bug 1041833
+skip-if(Android) pref(layout.css.scroll-behavior.enabled,true) pref(layout.css.scroll-behavior.property-enabled,true) == scroll-behavior-9.html scroll-behavior-9.html?ref # see bug 1041833
 skip-if(B2G&&browserIsRemote) HTTP == simple-1.html simple-1.html?ref
 skip-if(B2G) HTTP == subpixel-1.html#d subpixel-1-ref.html#d
 fuzzy-if(Android,4,120) HTTP == text-1.html text-1.html?ref
 fuzzy-if(Android,4,120) HTTP == text-2.html?up text-2.html?ref
 skip-if(B2G) fuzzy-if(Android&&AndroidVersion<15,251,722) fuzzy-if(d2d,1,4) HTTP == transformed-1.html transformed-1.html?ref
 HTTP == transformed-1.html?up transformed-1.html?ref
 fuzzy-if(Android,5,20000) == uncovering-1.html uncovering-1-ref.html
 fuzzy-if(Android,5,20000) == uncovering-2.html uncovering-2-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/scrolling/scroll-behavior-8.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<head>
+    <meta charset="utf-8">
+    <title>Testcase for bug 1010538 - Dynamically change scroll-behavior</title>
+    <style type="text/css">
+
+        html,body {
+            color: black;
+            background-color: white;
+            font-size: 16px;
+            padding: 0;
+            margin: 0;
+        }
+
+        .a_box {
+            position: relative;
+            left: 0px;
+            top: 0px;
+            width: 20px;
+            height: 20px;
+            background: blue;
+        }
+
+        .another_box {
+            position: relative;
+            left: 2000px;
+            top: 2000px;
+            width: 20px;
+            height: 20px;
+            background: green;
+        }
+
+        .scroll_box {
+            width: 150px;
+            height: 150px;
+            overflow: scroll;
+        }
+
+        #scroll_2 {
+            scroll-behavior: auto;
+        }
+
+        #scroll_3 {
+            scroll-behavior: smooth;
+        }
+
+    </style>
+</head>
+<body>
+  <div id="scroll_1" class="scroll_box">
+    <div id="box1a" class="a_box"></div>
+    <div id="box1b" class="another_box"></div>
+  </div>
+  <div id="scroll_2" class="scroll_box">
+    <div id="box2a" class="a_box"></div>
+    <div id="box2b" class="another_box"></div>
+  </div>
+  <div id="scroll_3" class="scroll_box">
+    <div id="box3a" class="a_box"></div>
+    <div id="box3b" class="another_box"></div>
+  </div>
+<script>
+  function doTest() {
+    if (document.location.search != '?ref') {
+      // Expect smooth scroll:
+      document.getElementById("scroll_1").style.scrollBehavior = "smooth";
+      document.getElementById("scroll_1").scrollTo({left: 0, top: 0});
+      document.getElementById("scroll_2").style.scrollBehavior = "smooth";
+      document.getElementById("scroll_2").scrollTo({left: 0, top: 0});
+
+      // Expect instant scroll:
+      document.getElementById("scroll_3").style.scrollBehavior = "auto";
+      document.getElementById("scroll_3").scrollTo({left: 0, top: 0});
+    } else {
+      document.getElementById("scroll_1").scrollTo({left: 0, top: 0, behavior: "smooth"});
+      document.getElementById("scroll_2").scrollTo({left: 0, top: 0, behavior: "smooth"});
+      document.getElementById("scroll_3").scrollTo({left: 0, top: 0, behavior: "instant"});
+    }
+
+    // Interrupt any smooth scrolling
+    for (var i=1; i <= 3; i++) {
+      document.getElementById("scroll_" + i).scrollTo();
+    }
+
+    document.documentElement.removeAttribute("class");
+  }
+
+  for (var i=1; i <= 3; i++) {
+    document.getElementById("box" + i + "b")
+      .scrollIntoView({block: "start", behavior: "instant"});
+  }
+
+  window.addEventListener("MozReftestInvalidate", doTest, false);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/scrolling/scroll-behavior-9.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<head>
+    <meta charset="utf-8">
+    <title>Testcase for bug 1082098, smooth scrolling expected after dynamically setting scroll-behavior on body</title>
+    <style type="text/css">
+
+        html,body {
+            color: black;
+            background-color: white;
+            font-size: 16px;
+            padding: 0;
+            margin: 0;
+        }
+
+        #a_box {
+            position: relative;
+            left: 10px;
+            top: 10px;
+            width: 20px;
+            height: 20px;
+            background: blue;
+        }
+
+        #another_box {
+            position: relative;
+            left: 2000px;
+            top: 2000px;
+            width: 20px;
+            height: 20px;
+            background: green;
+        }
+
+    </style>
+</head>
+<body>
+  <div id="a_box"></div>
+  <div id="another_box"></div>
+<script>
+  function doTest() {
+    if (document.location.search != '?ref') {
+      // Scroll - expected to be smooth
+      window.scrollTo({left: 500, top: 500});
+      // Interrupt smooth scrolling
+      window.scrollTo({left: window.scrollX, top: window.scrollY});
+      // If scroll was not performed smoothly, we would be at 500,500 now
+    }
+    document.documentElement.removeAttribute("class");
+  }
+  window.scrollTo({left: 0, top: 0, behavior: "instant"});
+  document.body.style.scrollBehavior = "smooth";
+  window.addEventListener("MozReftestInvalidate", doTest, false);
+</script>
+</body>
+</html>
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2672,19 +2672,30 @@ nsChangeHint nsStyleDisplay::CalcDiffere
   nsChangeHint hint = nsChangeHint(0);
 
   if (!EqualURIs(mBinding, aOther.mBinding)
       || mPosition != aOther.mPosition
       || mDisplay != aOther.mDisplay
       || (mFloats == NS_STYLE_FLOAT_NONE) != (aOther.mFloats == NS_STYLE_FLOAT_NONE)
       || mOverflowX != aOther.mOverflowX
       || mOverflowY != aOther.mOverflowY
+      || mScrollBehavior != aOther.mScrollBehavior
       || mResize != aOther.mResize)
     NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
 
+  /* Note: When mScrollBehavior is changed, the nsChangeHint_NeutralChange is
+   * not sufficient to enter nsCSSFrameConstructor::PropagateScrollToViewport.
+   * By using the same hint as used when the overflow css property changes,
+   * nsChangeHint_ReconstructFrame, PropagateScrollToViewport will be called.
+   *
+   * The scroll-behavior css property is not expected to change often (the
+   * CSSOM-View DOM methods are likely to be used in those cases); however,
+   * if this does become common perhaps a faster-path might be worth while.
+   */
+
   if ((mAppearance == NS_THEME_TEXTFIELD &&
        aOther.mAppearance != NS_THEME_TEXTFIELD) ||
       (mAppearance != NS_THEME_TEXTFIELD &&
        aOther.mAppearance == NS_THEME_TEXTFIELD)) {
     // This is for <input type=number> where we allow authors to specify a
     // |-moz-appearance:textfield| to get a control without a spinner. (The
     // spinner is present for |-moz-appearance:number-input| but also other
     // values such as 'none'.) We need to reframe since we want to use
@@ -2844,18 +2855,17 @@ nsChangeHint nsStyleDisplay::CalcDiffere
        mAnimations != aOther.mAnimations ||
        mAnimationTimingFunctionCount != aOther.mAnimationTimingFunctionCount ||
        mAnimationDurationCount != aOther.mAnimationDurationCount ||
        mAnimationDelayCount != aOther.mAnimationDelayCount ||
        mAnimationNameCount != aOther.mAnimationNameCount ||
        mAnimationDirectionCount != aOther.mAnimationDirectionCount ||
        mAnimationFillModeCount != aOther.mAnimationFillModeCount ||
        mAnimationPlayStateCount != aOther.mAnimationPlayStateCount ||
-       mAnimationIterationCountCount != aOther.mAnimationIterationCountCount ||
-       mScrollBehavior != aOther.mScrollBehavior)) {
+       mAnimationIterationCountCount != aOther.mAnimationIterationCountCount)) {
     NS_UpdateHint(hint, nsChangeHint_NeutralChange);
   }
 
   return hint;
 }
 
 // --------------------
 // nsStyleVisibility
--- a/memory/replace/dmd/test/SmokeDMD.cpp
+++ b/memory/replace/dmd/test/SmokeDMD.cpp
@@ -277,17 +277,17 @@ RunTests()
   char* s;
 
   // This equals the sample size, and so is reported exactly.  It should be
   // listed before records of the same size that are sampled.
   s = (char*) malloc(128);
   UseItOrLoseIt(s, seven);
 
   // This exceeds the sample size, and so is reported exactly.
-  s = (char*) malloc(144);
+  s = (char*) malloc(160);
   UseItOrLoseIt(s, seven);
 
   // These together constitute exactly one sample.
   for (int i = 0; i < seven + 9; i++) {
     s = (char*) malloc(8);
     UseItOrLoseIt(s, seven);
   }
 
--- a/memory/replace/dmd/test/full-heap-sampled-expected.txt
+++ b/memory/replace/dmd/test/full-heap-sampled-expected.txt
@@ -7,74 +7,74 @@ Invocation {
 }
 
 #-----------------------------------------------------------------
 
 Live {
   ~4 blocks in heap block record 1 of 7
   ~512 bytes (~512 requested / ~0 slop)
   Individual block sizes: ~128 x 3; 128
-  35.96% of the heap (35.96% cumulative)
+  35.56% of the heap (35.56% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Live {
   1 block in heap block record 2 of 7
   256 bytes (256 requested / 0 slop)
-  17.98% of the heap (53.93% cumulative)
+  17.78% of the heap (53.33% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Live {
   1 block in heap block record 3 of 7
-  144 bytes (144 requested / 0 slop)
-  10.11% of the heap (64.04% cumulative)
+  160 bytes (160 requested / 0 slop)
+  11.11% of the heap (64.44% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Live {
   1 block in heap block record 4 of 7
   128 bytes (128 requested / 0 slop)
-  8.99% of the heap (73.03% cumulative)
+  8.89% of the heap (73.33% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Live {
   ~1 block in heap block record 5 of 7
   ~128 bytes (~128 requested / ~0 slop)
-  8.99% of the heap (82.02% cumulative)
+  8.89% of the heap (82.22% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Live {
   ~1 block in heap block record 6 of 7
   ~128 bytes (~128 requested / ~0 slop)
-  8.99% of the heap (91.01% cumulative)
+  8.89% of the heap (91.11% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Live {
   ~1 block in heap block record 7 of 7
   ~128 bytes (~128 requested / ~0 slop)
-  8.99% of the heap (100.00% cumulative)
+  8.89% of the heap (100.00% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 #-----------------------------------------------------------------
 
 Summary {
-  Total: ~1,424 bytes in ~10 blocks
+  Total: ~1,440 bytes in ~10 blocks
 }
 
--- a/memory/replace/dmd/test/full-reports-sampled-expected.txt
+++ b/memory/replace/dmd/test/full-reports-sampled-expected.txt
@@ -11,88 +11,88 @@ Invocation {
 # no twice-reported heap blocks
 
 #-----------------------------------------------------------------
 
 Unreported {
   ~4 blocks in heap block record 1 of 7
   ~512 bytes (~512 requested / ~0 slop)
   Individual block sizes: ~128 x 3; 128
-  35.96% of the heap (35.96% cumulative)
-  35.96% of unreported (35.96% cumulative)
+  35.56% of the heap (35.56% cumulative)
+  35.56% of unreported (35.56% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Unreported {
   1 block in heap block record 2 of 7
   256 bytes (256 requested / 0 slop)
-  17.98% of the heap (53.93% cumulative)
-  17.98% of unreported (53.93% cumulative)
+  17.78% of the heap (53.33% cumulative)
+  17.78% of unreported (53.33% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Unreported {
   1 block in heap block record 3 of 7
-  144 bytes (144 requested / 0 slop)
-  10.11% of the heap (64.04% cumulative)
-  10.11% of unreported (64.04% cumulative)
+  160 bytes (160 requested / 0 slop)
+  11.11% of the heap (64.44% cumulative)
+  11.11% of unreported (64.44% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Unreported {
   1 block in heap block record 4 of 7
   128 bytes (128 requested / 0 slop)
-  8.99% of the heap (73.03% cumulative)
-  8.99% of unreported (73.03% cumulative)
+  8.89% of the heap (73.33% cumulative)
+  8.89% of unreported (73.33% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Unreported {
   ~1 block in heap block record 5 of 7
   ~128 bytes (~128 requested / ~0 slop)
-  8.99% of the heap (82.02% cumulative)
-  8.99% of unreported (82.02% cumulative)
+  8.89% of the heap (82.22% cumulative)
+  8.89% of unreported (82.22% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Unreported {
   ~1 block in heap block record 6 of 7
   ~128 bytes (~128 requested / ~0 slop)
-  8.99% of the heap (91.01% cumulative)
-  8.99% of unreported (91.01% cumulative)
+  8.89% of the heap (91.11% cumulative)
+  8.89% of unreported (91.11% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 Unreported {
   ~1 block in heap block record 7 of 7
   ~128 bytes (~128 requested / ~0 slop)
-  8.99% of the heap (100.00% cumulative)
-  8.99% of unreported (100.00% cumulative)
+  8.89% of the heap (100.00% cumulative)
+  8.89% of unreported (100.00% cumulative)
   Allocated at {
     #01: ... DMD.cpp ...
   }
 }
 
 #-----------------------------------------------------------------
 
 # no once-reported heap blocks
 
 #-----------------------------------------------------------------
 
 Summary {
-  Total:                ~1,424 bytes (100.00%) in     ~10 blocks (100.00%)
-  Unreported:           ~1,424 bytes (100.00%) in     ~10 blocks (100.00%)
+  Total:                ~1,440 bytes (100.00%) in     ~10 blocks (100.00%)
+  Unreported:           ~1,440 bytes (100.00%) in     ~10 blocks (100.00%)
   Once-reported:            ~0 bytes (  0.00%) in      ~0 blocks (  0.00%)
   Twice-reported:           ~0 bytes (  0.00%) in      ~0 blocks (  0.00%)
 }
 
--- a/mobile/android/base/tests/robocop_getusermedia.html
+++ b/mobile/android/base/tests/robocop_getusermedia.html
@@ -1,30 +1,41 @@
 <!DOCTYPE html>
 <html><head>
   <title>gUM Test Page</title>
   <meta http-equiv="content-type" content="text/html; charset=UTF-8" charset="utf-8">
 </head>
 <body>
+  <div id="content"></div>
   <script type="application/javascript">
   var video_status = false;
   var video = document.createElement("video");
   video.setAttribute("width", 640);
   video.setAttribute("height", 480);
 
   var audio_status = false;
   var audio = document.createElement("audio");
   audio.setAttribute("controls", true);
 
+  var content = document.getElementById("content");
+  document.title = "gUM Test Page";
+
   startAudioVideo();
 
   function startAudioVideo() {
     video_status = true;
     audio_status = true;
-    startMedia({video:true, audio:true});
+    mediaConstraints = {
+      video: {
+        mozMediaSource: "browser",
+        mediaSource: "browser"
+      },
+      audio: true
+    };
+    startMedia(mediaConstraints);
   }
 
   function stopMedia() {
     if (video_status) {
       video.mozSrcObject.stop();
       video.mozSrcObject = null;
       content.removeChild(video);
       capturing = false;
@@ -36,28 +47,40 @@
       content.removeChild(audio);
       audio_status = false;
     }
   }
 
   function startMedia(param) {
     try {
       window.navigator.mozGetUserMedia(param, function(stream) {
-        message.innerHTML = "<p>Success!</p>";
         if (video_status) {
           content.appendChild(video);
           video.mozSrcObject = stream;
           video.play();
         }
         if (audio_status) {
           content.appendChild(audio);
           audio.mozSrcObject = stream;
           audio.play();
         }
+        var audioTracks = stream.getAudioTracks();
+        var videoTracks = stream.getVideoTracks();
+        document.title = "";
+        if (audioTracks.length > 0) {
+          document.title += "audio";
+        }
+        if (videoTracks.length > 0) {
+          document.title += "video";
+        }
+        document.title += " gumtest";
+        audio.mozSrcObject.stop();
+        video.mozSrcObject.stop();
       }, function(err) {
+        document.title = "failed gumtest";
         stopMedia();
       });
     } catch(e) {
       stopMedia();
     }
   }
 </script>
-</body></html>
\ No newline at end of file
+</body></html>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/robocop_getusermedia2.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html><head>
+  <title>gUM Test Page</title>
+  <meta http-equiv="content-type" content="text/html; charset=UTF-8" charset="utf-8">
+</head>
+<body>
+  <div id="content"></div>
+  <script type="application/javascript">
+  var video_status = false;
+  var video = document.createElement("video");
+  video.setAttribute("width", 640);
+  video.setAttribute("height", 480);
+
+  var audio_status = false;
+  var audio = document.createElement("audio");
+  audio.setAttribute("controls", true);
+
+  var content = document.getElementById("content");
+  document.title = "gUM Test Page";
+
+  startAudioVideo();
+
+  function startAudioVideo() {
+    video_status = true;
+    audio_status = true;
+    mediaConstraints = {
+      video: true,
+      audio: true
+    };
+    startMedia(mediaConstraints);
+  }
+
+  function stopMedia() {
+    if (video_status) {
+      video.mozSrcObject.stop();
+      video.mozSrcObject = null;
+      content.removeChild(video);
+      capturing = false;
+      video_status = false;
+    }
+    if (audio_status) {
+      audio.mozSrcObject.stop();
+      audio.mozSrcObject = null;
+      content.removeChild(audio);
+      audio_status = false;
+    }
+  }
+
+  function startMedia(param) {
+    try {
+      window.navigator.mozGetUserMedia(param, function(stream) {
+        if (video_status) {
+          content.appendChild(video);
+          video.mozSrcObject = stream;
+          video.play();
+        }
+        if (audio_status) {
+          content.appendChild(audio);
+          audio.mozSrcObject = stream;
+          audio.play();
+        }
+        var audioTracks = stream.getAudioTracks();
+        var videoTracks = stream.getVideoTracks();
+        document.title = "";
+        if (audioTracks.length > 0) {
+          document.title += "audio";
+        }
+        if (videoTracks.length > 0) {
+          document.title += "video";
+        }
+        document.title += " gumtest";
+        audio.mozSrcObject.stop();
+        video.mozSrcObject.stop();
+      }, function(err) {
+        document.title = "failed gumtest";
+        stopMedia();
+      });
+    } catch(e) {
+      stopMedia();
+    }
+  }
+</script>
+</body></html>
--- a/mobile/android/base/tests/testGetUserMedia.java
+++ b/mobile/android/base/tests/testGetUserMedia.java
@@ -1,30 +1,143 @@
 package org.mozilla.gecko.tests;
 
+import android.widget.Spinner;
+import android.view.View;
+import com.jayway.android.robotium.solo.Condition;
 import android.hardware.Camera;
 import android.os.Build;
 
 public class testGetUserMedia extends BaseTest {
     public void testGetUserMedia() {
-        String GUM_URL = getAbsoluteUrl("/robocop/robocop_getusermedia.html");
+        String GUM_CAMERA_URL = getAbsoluteUrl("/robocop/robocop_getusermedia2.html");
+        String GUM_TAB_URL = getAbsoluteUrl("/robocop/robocop_getusermedia.html");
+        // Browser constraint needs HTTPS
+        String GUM_TAB_HTTPS_URL = GUM_TAB_URL.replace("http://mochi.test:8888", "https://example.com");
 
         String GUM_MESSAGE = "Would you like to share your camera and microphone with";
-        String GUM_ALLOW = "Share";
-        String GUM_DENY = "Don't share";
+        String GUM_ALLOW = "^Share$";
+        String GUM_DENY = "^Don't Share$";
+
+        String GUM_BACK_CAMERA = "Back facing camera";
+        String GUM_SELECT_TAB = "Choose a tab to stream";
+
+        String GUM_PAGE_TITLE = "gUM Test Page";
+        String GUM_PAGE_FAILED = "failed gumtest";
+        String GUM_PAGE_AUDIO = "audio gumtest";
+        String GUM_PAGE_VIDEO = "video gumtest";
+        String GUM_PAGE_AUDIOVIDEO = "audiovideo gumtest";
 
         blockForGeckoReady();
 
-        // Only try GUM test if the device has a camera. If there's a working Camera,
-        // we'll assume there is a working audio device as well.
-        // getNumberOfCameras is Gingerbread/9+
-        // We could avoid that requirement by trying to open a Camera but we
-        // already know our 2.2/Tegra test devices don't have them.
-        if (Build.VERSION.SDK_INT >= 9) {
-            if (Camera.getNumberOfCameras() > 0) {
-                // Test GUM notification
-                inputAndLoadUrl(GUM_URL);
-                waitForText(GUM_MESSAGE);
-                mAsserter.is(mSolo.searchText(GUM_MESSAGE), true, "GetUserMedia doorhanger has been displayed");
+        // Only try GUM test if the device has a camera (emulation).
+        if (Camera.getNumberOfCameras() <= 0) {
+            return;
+        }
+
+        // Tests on Camera page will test camera enumeration code, but
+        // the actual cameras don't seem to work on the emulators, so
+        // the enumeration is all that gets tested.
+
+        // Test GUM notification showing
+        inputAndLoadUrl(GUM_CAMERA_URL);
+        waitForText(GUM_MESSAGE);
+        mAsserter.is(mSolo.searchText(GUM_MESSAGE), true, "getUserMedia doorhanger has been displayed");
+        waitForSpinner();
+        // At least one camera detected
+        mAsserter.is(mSolo.searchText(GUM_BACK_CAMERA), true, "getUserMedia found a camera");
+        mSolo.clickOnButton(GUM_DENY);
+        waitForTextDismissed(GUM_MESSAGE);
+        mAsserter.is(mSolo.searchText(GUM_MESSAGE), false, "getUserMedia doorhanger hidden after dismissal");
+        verifyPageTitle(GUM_PAGE_FAILED, GUM_CAMERA_URL);
+
+        // Cameras don't work on the testing hardware, so stream a tab
+        inputAndLoadUrl(GUM_TAB_HTTPS_URL);
+        waitForText(GUM_MESSAGE);
+        mAsserter.is(mSolo.searchText(GUM_MESSAGE), true, "getUserMedia doorhanger has been displayed");
+        waitForSpinner();
+        mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Video source selection available");
+        mAsserter.is(mSolo.searchText("MICROPHONE TO USE"), true, "Microphone selection available");
+        mAsserter.is(mSolo.searchText("Microphone 1"), true, "Microphone 1 available");
+        mSolo.clickOnText("Microphone 1");
+        waitForText("No Audio");
+        mAsserter.is(mSolo.searchText("No Audio"), true, "No 'No Audio' selection available");
+        mSolo.clickOnText("No Audio");
+        waitForTextDismissed("Microphone 1");
+        mAsserter.is(mSolo.searchText("Microphone 1"), false, "Audio selection hidden after dismissal");
+        mAsserter.is(mSolo.searchText(GUM_ALLOW), true, "Share button available after selection");
+        mSolo.clickOnButton(GUM_ALLOW);
+        waitForTextDismissed(GUM_MESSAGE);
+        mAsserter.is(mSolo.searchText(GUM_MESSAGE), false, "getUserMedia doorhanger hidden after dismissal");
+        waitForText(GUM_SELECT_TAB);
+        mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Tab selection dialog displayed");
+        mSolo.clickOnText(GUM_PAGE_TITLE);
+        waitForTextDismissed(GUM_SELECT_TAB);
+        mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), false, "Tab selection dialog hidden");
+        verifyPageTitle(GUM_PAGE_VIDEO, GUM_TAB_HTTPS_URL);
+
+        // Android 2.3 testers fail because of audio issues:
+        // E/AudioRecord(  650): Unsupported configuration: sampleRate 44100, format 1, channelCount 1
+        // E/libOpenSLES(  650): android_audioRecorder_realize(0x26d7d8) error creating AudioRecord object
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            return;
+        }
+
+        inputAndLoadUrl(GUM_TAB_HTTPS_URL);
+        waitForText(GUM_MESSAGE);
+        mAsserter.is(mSolo.searchText(GUM_MESSAGE), true, "getUserMedia doorhanger has been displayed");
+
+        waitForSpinner();
+        mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Video source selection available");
+        mSolo.clickOnButton(GUM_ALLOW);
+        waitForTextDismissed(GUM_MESSAGE);
+        waitForText(GUM_SELECT_TAB);
+        mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Tab selection dialog displayed");
+        mSolo.clickOnText(GUM_PAGE_TITLE);
+        waitForTextDismissed(GUM_SELECT_TAB);
+        mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), false, "Tab selection dialog hidden");
+        verifyPageTitle(GUM_PAGE_AUDIOVIDEO, GUM_TAB_HTTPS_URL);
+
+        inputAndLoadUrl(GUM_TAB_HTTPS_URL);
+        waitForText(GUM_MESSAGE);
+        mAsserter.is(mSolo.searchText(GUM_MESSAGE), true, "getUserMedia doorhanger has been displayed");
+
+        waitForSpinner();
+        mAsserter.is(mSolo.searchText(GUM_SELECT_TAB), true, "Video source selection available");
+        mSolo.clickOnText(GUM_SELECT_TAB);
+        waitForText("No Video");
+        mAsserter.is(mSolo.searchText("No Video"), true, "'No video' source selection available");
+        mSolo.clickOnText("No Video");
+        waitForTextDismissed(GUM_SELECT_TAB);
+        mSolo.clickOnButton(GUM_ALLOW);
+        waitForTextDismissed(GUM_MESSAGE);
+        mAsserter.is(mSolo.searchText(GUM_MESSAGE), false, "getUserMedia doorhanger hidden after dismissal");
+        verifyPageTitle(GUM_PAGE_AUDIO, GUM_TAB_HTTPS_URL);
+    }
+
+    // wait for a Spinner view that is clickable
+    private void waitForSpinner() {
+        waitForCondition(new Condition() {
+            @Override
+            public boolean isSatisfied() {
+                for (Spinner view : mSolo.getCurrentViews(Spinner.class)) {
+                    if (view.isClickable() &&
+                        view.getVisibility() == View.VISIBLE &&
+                        view.getWidth() > 0 &&
+                        view.getHeight() > 0) {
+                        return true;
+                    }
+                }
+                return false;
             }
-        }
+        }, MAX_WAIT_MS);
+    }
+
+    // wait until the specified text is *not* displayed
+    private void waitForTextDismissed(final String text) {
+        waitForCondition(new Condition() {
+            @Override
+            public boolean isSatisfied() {
+                return !mSolo.searchText(text);
+            }
+        }, MAX_WAIT_MS);
     }
 }
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -123,16 +123,19 @@ pref("dom.indexedDB.experimental", false
 // Whether or not Web Workers are enabled.
 pref("dom.workers.enabled", true);
 // The number of workers per domain allowed to run concurrently.
 pref("dom.workers.maxPerDomain", 20);
 
 // Whether or not Shared Web Workers are enabled.
 pref("dom.workers.sharedWorkers.enabled", true);
 
+// WebSocket in workers are enabled.
+pref("dom.workers.websocket.enabled", true);
+
 // Service workers
 pref("dom.serviceWorkers.enabled", false);
 
 // Whether nonzero values can be returned from performance.timing.*
 pref("dom.enable_performance", true);
 
 // Whether resource timing will be gathered and returned by performance.GetEntries*
 pref("dom.enable_resource_timing", true);
@@ -383,20 +386,20 @@ pref("media.getusermedia.playout_delay",
 #endif
 #endif
 
 #if !defined(ANDROID)
 pref("media.getusermedia.screensharing.enabled", true);
 #endif
 
 #ifdef RELEASE_BUILD
-pref("media.getusermedia.screensharing.allowed_domains", "webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com");
+pref("media.getusermedia.screensharing.allowed_domains", "webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,example.com");
 #else
  // temporary value, not intended for release - bug 1049087
-pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com");
+pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webex.com,*.webex.com,collaborate.com,*.collaborate.com,projectsquared.com,*.projectsquared.com,example.com");
 #endif
 // OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor
 pref("media.getusermedia.screensharing.allow_on_old_platforms", false);
 
 // TextTrack support
 pref("media.webvtt.enabled", true);
 pref("media.webvtt.regions.enabled", false);
 
@@ -1287,19 +1290,16 @@ pref("network.http.enforce-framing.http1
 // in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
 // Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
 // per Section 4.7 "Low-Latency Data Service Class".
 pref("network.ftp.data.qos", 0);
 pref("network.ftp.control.qos", 0);
 
 // </http>
 
-// <ws>: WebSocket
-pref("network.websocket.enabled", true);
-
 // 2147483647 == PR_INT32_MAX == ~2 GB
 pref("network.websocket.max-message-size", 2147483647);
 
 // Should we automatically follow http 3xx redirects during handshake
 pref("network.websocket.auto-follow-http-redirects", false);
 
 // the number of seconds to wait for websocket connection to be opened
 pref("network.websocket.timeout.open", 20);
@@ -3810,16 +3810,21 @@ pref("webgl.prefer-16bpp", false);
 pref("webgl.default-no-alpha", false);
 pref("webgl.force-layers-readback", false);
 pref("webgl.lose-context-on-memory-preasure", false);
 pref("webgl.can-lose-context-in-foreground", true);
 pref("webgl.restore-context-when-visible", true);
 pref("webgl.max-warnings-per-context", 32);
 pref("webgl.enable-draft-extensions", false);
 pref("webgl.enable-privileged-extensions", false);
+#ifdef XP_WIN
+pref("webgl.angle.try-d3d11", false);
+pref("webgl.angle.force-d3d11", false);
+#endif
+
 #ifdef MOZ_WIDGET_GONK
 pref("gfx.gralloc.fence-with-readpixels", false);
 #endif
 
 
 // Stagefright prefs
 pref("stagefright.force-enabled", false);
 pref("stagefright.disabled", false);
--- a/netwerk/base/src/Dashboard.cpp
+++ b/netwerk/base/src/Dashboard.cpp
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http:mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/NetDashboardBinding.h"
 #include "mozilla/dom/ToJSValue.h"
+#include "mozilla/ErrorNames.h"
 #include "mozilla/net/Dashboard.h"
 #include "mozilla/net/HttpInfo.h"
 #include "nsHttp.h"
 #include "nsICancelable.h"
 #include "nsIDNSService.h"
 #include "nsIDNSRecord.h"
 #include "nsIInputStream.h"
 #include "nsISocketTransport.h"
@@ -45,16 +46,18 @@ public:
     nsIThread *mThread;
 
 private:
     virtual ~SocketData()
     {
     }
 };
 
+static void GetErrorString(nsresult rv, nsAString& errorString);
+
 NS_IMPL_ISUPPORTS0(SocketData)
 
 
 class HttpData
     : public nsISupports
 {
     virtual ~HttpData()
     {
@@ -166,17 +169,17 @@ NS_IMPL_ISUPPORTS(ConnectionData, nsITra
 NS_IMETHODIMP
 ConnectionData::OnTransportStatus(nsITransport *aTransport, nsresult aStatus,
                                   uint64_t aProgress, uint64_t aProgressMax)
 {
     if (aStatus == NS_NET_STATUS_CONNECTED_TO) {
         StopTimer();
     }
 
-    CopyASCIItoUTF16(Dashboard::GetErrorString(aStatus), mStatus);
+    GetErrorString(aStatus, mStatus);
     nsCOMPtr<nsIRunnable> event =
         NS_NewRunnableMethodWithArg<nsRefPtr<ConnectionData> >
         (mDashboard, &Dashboard::GetConnectionStatus, this);
     mThread->Dispatch(event, NS_DISPATCH_NORMAL);
 
     return NS_OK;
 }
 
@@ -311,17 +314,17 @@ LookupHelper::ConstructAnswer(LookupArgu
         while (hasMore) {
            nsCString nextAddress;
            aRecord->GetNextAddrAsString(nextAddress);
            CopyASCIItoUTF16(nextAddress, *addresses.AppendElement());
            aRecord->HasMore(&hasMore);
         }
     } else {
         dict.mAnswer = false;
-        CopyASCIItoUTF16(Dashboard::GetErrorString(mStatus), dict.mError);
+        GetErrorString(mStatus, dict.mError);
     }
 
     JS::RootedValue val(cx);
     if (!ToJSValue(cx, dict, &val)) {
         return NS_ERROR_FAILURE;
     }
 
     this->mCallback->OnDashboardDataAvailable(val);
@@ -801,17 +804,17 @@ Dashboard::RequestConnection(const nsACS
     connectionData->mTimeout = aTimeout;
 
     connectionData->mCallback =
         new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
     connectionData->mThread = NS_GetCurrentThread();
 
     rv = TestNewConnection(connectionData);
     if (NS_FAILED(rv)) {
-        CopyASCIItoUTF16(GetErrorString(rv), connectionData->mStatus);
+        mozilla::net::GetErrorString(rv, connectionData->mStatus);
         nsCOMPtr<nsIRunnable> event =
             NS_NewRunnableMethodWithArg<nsRefPtr<ConnectionData> >
             (this, &Dashboard::GetConnectionStatus, connectionData);
         connectionData->mThread->Dispatch(event, NS_DISPATCH_NORMAL);
         return rv;
     }
 
     return NS_OK;
@@ -884,42 +887,35 @@ typedef struct
 {
     nsresult key;
     const char *error;
 } ErrorEntry;
 
 #undef ERROR
 #define ERROR(key, val) {key, #key}
 
-ErrorEntry errors[] = {
-    #include "ErrorList.h"
-};
-
 ErrorEntry socketTransportStatuses[] = {
         ERROR(NS_NET_STATUS_RESOLVING_HOST,  FAILURE(3)),
         ERROR(NS_NET_STATUS_RESOLVED_HOST,   FAILURE(11)),
         ERROR(NS_NET_STATUS_CONNECTING_TO,   FAILURE(7)),
         ERROR(NS_NET_STATUS_CONNECTED_TO,    FAILURE(4)),
         ERROR(NS_NET_STATUS_SENDING_TO,      FAILURE(5)),
         ERROR(NS_NET_STATUS_WAITING_FOR,     FAILURE(10)),
         ERROR(NS_NET_STATUS_RECEIVING_FROM,  FAILURE(6)),
 };
 #undef ERROR
 
-const char *
-Dashboard::GetErrorString(nsresult rv)
+
+static void
+GetErrorString(nsresult rv, nsAString& errorString)
 {
-    int length = sizeof(socketTransportStatuses) / sizeof(ErrorEntry);
-    for (int i = 0;i < length;i++)
+    for (size_t i = 0; i < ArrayLength(socketTransportStatuses); ++i) {
         if (socketTransportStatuses[i].key == rv) {
-            return socketTransportStatuses[i].error;
+            errorString.AssignASCII(socketTransportStatuses[i].error);
+            return;
         }
-
-    length = sizeof(errors) / sizeof(ErrorEntry);
-    for (int i = 0;i < length;i++)
-        if (errors[i].key == rv) {
-            return errors[i].error;
-        }
-
-    return nullptr;
+    }
+    nsAutoCString errorCString;
+    mozilla::GetErrorName(rv, errorCString);
+    CopyUTF8toUTF16(errorCString, errorString);
 }
 
 } } // namespace mozilla::net
--- a/netwerk/dns/effective_tld_names.dat
+++ b/netwerk/dns/effective_tld_names.dat
@@ -1593,29 +1593,29 @@ gov.jo
 mil.jo
 name.jo
 
 // jobs : http://en.wikipedia.org/wiki/.jobs
 jobs
 
 // jp : http://en.wikipedia.org/wiki/.jp
 // http://jprs.co.jp/en/jpdomain.html
-// Submitted by registry <info@jprs.jp> 2014-02-28
+// Submitted by registry <info@jprs.jp> 2014-10-30
 jp
 // jp organizational type names
 ac.jp
 ad.jp
 co.jp
 ed.jp
 go.jp
 gr.jp
 lg.jp
 ne.jp
 or.jp
-// jp preficture type names
+// jp prefecture type names
 aichi.jp
 akita.jp
 aomori.jp
 chiba.jp
 ehime.jp
 fukui.jp
 fukuoka.jp
 fukushima.jp
@@ -1653,16 +1653,63 @@ tochigi.jp
 tokushima.jp
 tokyo.jp
 tottori.jp
 toyama.jp
 wakayama.jp
 yamagata.jp
 yamaguchi.jp
 yamanashi.jp
+栃木.jp
+愛知.jp
+愛媛.jp
+兵庫.jp
+熊本.jp
+茨城.jp
+北海道.jp
+千葉.jp
+和歌山.jp
+長崎.jp
+長野.jp
+新潟.jp
+青森.jp
+静岡.jp
+東京.jp
+石川.jp
+埼玉.jp
+三重.jp
+京都.jp
+佐賀.jp
+大分.jp
+大阪.jp
+奈良.jp
+宮城.jp
+宮崎.jp
+富山.jp
+山口.jp
+山形.jp
+山梨.jp
+岩手.jp
+岐阜.jp
+岡山.jp
+島根.jp
+広島.jp
+徳島.jp
+沖縄.jp
+滋賀.jp
+神奈川.jp
+福井.jp
+福岡.jp
+福島.jp
+秋田.jp
+群馬.jp
+香川.jp
+高知.jp
+鳥取.jp
+鹿児島.jp
 // jp geographic type names
 // http://jprs.jp/doc/rule/saisoku-1.html
 *.kawasaki.jp
 *.kitakyushu.jp
 *.kobe.jp
 *.nagoya.jp
 *.sapporo.jp
 *.sendai.jp
@@ -5603,17 +5650,17 @@ kuban.ru
 kurgan.ru
 kursk.ru
 lipetsk.ru
 magadan.ru
 mari.ru
 mari-el.ru
 marine.ru
 mordovia.ru
-mosreg.ru
+// mosreg.ru  Bug 1090800 - removed at request of Aleksey Konstantinov <konstantinovav@mosreg.ru>
 msk.ru
 murmansk.ru
 nalchik.ru
 nnov.ru
 nov.ru
 novosibirsk.ru
 nsk.ru
 omsk.ru
@@ -6728,17 +6775,17 @@ xxx
 
 // zm : http://en.wikipedia.org/wiki/.zm
 *.zm
 
 // zw : http://en.wikipedia.org/wiki/.zw
 *.zw
 
 
-// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2014-09-02T12:02:06Z
+// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2014-10-04T06:02:06Z
 
 // abbott : 2014-07-24 Abbott Laboratories, Inc.
 abbott
 
 // abogado : 2014-04-24 Top Level Domain Holdings Limited
 abogado
 
 // academy : 2013-11-07 Half Oaks, LLC
@@ -6751,16 +6798,19 @@ accenture
 accountants
 
 // active : 2014-05-01 The Active Network, Inc
 active
 
 // actor : 2013-12-12 United TLD Holdco Ltd.
 actor
 
+// afl : 2014-10-02 Australian Football League
+afl
+
 // africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa
 africa
 
 // agency : 2013-11-14 Steel Falls, LLC
 agency
 
 // airforce : 2014-03-06 United TLD Holdco Ltd.
 airforce
@@ -6784,49 +6834,55 @@ aquarelle
 archi
 
 // army : 2014-03-06 United TLD Holdco Ltd.
 army
 
 // associates : 2014-03-06 Baxter Hill, LLC
 associates
 
-// attorney : 2014-03-20 undefined
+// attorney : 2014-03-20
 attorney
 
-// auction : 2014-03-20 undefined
+// auction : 2014-03-20
 auction
 
 // audio : 2014-03-20 Uniregistry, Corp.
 audio
 
 // autos : 2014-01-09 DERAutos, LLC
 autos
 
 // axa : 2013-12-19 AXA SA
 axa
 
-// band : 2014-06-12 Auburn Hollow, LLC
+// band : 2014-06-12
 band
 
+// bank : 2014-09-25 fTLD Registry Services LLC
+bank
+
 // bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
 bar
 
 // barcelona : 2014-07-24 Municipi de Barcelona
 barcelona
 
 // bargains : 2013-11-14 Half Hallow, LLC
 bargains
 
 // bauhaus : 2014-04-17 Werkhaus GmbH
 bauhaus
 
 // bayern : 2014-01-23 Bayern Connect GmbH
 bayern
 
+// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A.
+bbva
+
 // bcn : 2014-07-24 Municipi de Barcelona
 bcn
 
 // beer : 2014-01-09 Top Level Domain Holdings Limited
 beer
 
 // berlin : 2013-10-31 dotBERLIN GmbH & Co. KG
 berlin
@@ -6910,16 +6966,19 @@ cal
 camera
 
 // camp : 2013-11-07 Delta Dynamite, LLC
 camp
 
 // cancerresearch : 2014-05-15 Australian Cancer Research Foundation
 cancerresearch
 
+// canon : 2014-09-12 Canon Inc.
+canon
+
 // capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
 capetown
 
 // capital : 2014-03-06 Delta Mill, LLC
 capital
 
 // caravan : 2013-12-12 Caravan International, Inc.
 caravan
@@ -7030,43 +7089,49 @@ company
 computer
 
 // condos : 2013-12-05 Pine House, LLC
 condos
 
 // construction : 2013-09-16 Fox Dynamite, LLC
 construction
 
-// consulting : 2013-12-05 undefined
+// consulting : 2013-12-05
 consulting
 
 // contractors : 2013-09-10 Magic Woods, LLC
 contractors
 
 // cooking : 2013-11-21 Top Level Domain Holdings Limited
 cooking
 
 // cool : 2013-11-14 Koko Lake, LLC
 cool
 
+// corsica : 2014-09-25 Collectivité Territoriale de Corse
+corsica
+
 // country : 2013-12-19 Top Level Domain Holdings Limited
 country
 
 // credit : 2014-03-20 Snow Shadow, LLC
 credit
 
 // creditcard : 2014-03-20 Binky Frostbite, LLC
 creditcard
 
 // crs : 2014-04-03 Federated Co-operatives Limited
 crs
 
 // cruises : 2013-12-05 Spring Way, LLC
 cruises
 
+// csc : 2014-09-25 Alliance-One Services, Inc.
+csc
+
 // cuisinella : 2014-04-03 SALM S.A.S.
 cuisinella
 
 // cymru : 2014-05-08 Nominet UK
 cymru
 
 // dabur : 2014-02-06 Dabur India Limited
 dabur
@@ -7084,26 +7149,29 @@ dating
 datsun
 
 // day : 2014-01-30 Charleston Road Registry Inc.
 day
 
 // deals : 2014-05-22 Sand Sunset, LLC
 deals
 
-// degree : 2014-03-06 undefined
+// degree : 2014-03-06
 degree
 
+// delivery : 2014-09-11 Steel Station, LLC
+delivery
+
 // democrat : 2013-10-24 United TLD Holdco Ltd.
 democrat
 
 // dental : 2014-03-20 Tin Birch, LLC
 dental
 
-// dentist : 2014-03-20 undefined
+// dentist : 2014-03-20
 dentist
 
 // desi : 2013-11-14 Desi Networks LLC
 desi
 
 // diamonds : 2013-09-22 John Edge, LLC
 diamonds
 
@@ -7120,16 +7188,19 @@ direct
 directory
 
 // discount : 2014-03-06 Holly Hill, LLC
 discount
 
 // dnp : 2013-12-13 Dai Nippon Printing Co., Ltd.
 dnp
 
+// doha : 2014-09-18 Communications Regulatory Authority (CRA)
+doha
+
 // domains : 2013-10-17 Sugar Cross, LLC
 domains
 
 // doosan : 2014-04-03 Doosan Corporation
 doosan
 
 // durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
 durban
@@ -7144,16 +7215,19 @@ eat
 education
 
 // email : 2013-10-31 Spring Madison, LLC
 email
 
 // emerck : 2014-04-03 Merck KGaA
 emerck
 
+// energy : 2014-09-11 Binky Birch, LLC
+energy
+
 // engineer : 2014-03-06 United TLD Holdco Ltd.
 engineer
 
 // engineering : 2014-03-06 Romeo Canyon
 engineering
 
 // enterprises : 2013-09-20 Snow Oaks, LLC
 enterprises
@@ -7189,17 +7263,17 @@ exchange
 expert
 
 // exposed : 2013-12-05 Victor Beach, LLC
 exposed
 
 // fail : 2014-03-06 Atomic Pipe, LLC
 fail
 
-// fan : 2014-03-06 undefined
+// fan : 2014-03-06
 fan
 
 // farm : 2013-11-07 Just Maple, LLC
 farm
 
 // fashion : 2014-07-03 Top Level Domain Holdings Limited
 fashion
 
@@ -7234,17 +7308,17 @@ florist
 flsmidth
 
 // fly : 2014-05-08 Charleston Road Registry Inc.
 fly
 
 // foo : 2014-01-23 Charleston Road Registry Inc.
 foo
 
-// forsale : 2014-05-22 undefined
+// forsale : 2014-05-22
 forsale
 
 // foundation : 2013-12-05 John Dale, LLC
 foundation
 
 // frl : 2014-05-15 FRLregistry B.V.
 frl
 
@@ -7252,17 +7326,17 @@ frl
 frogans
 
 // fund : 2014-03-20 John Castle, LLC
 fund
 
 // furniture : 2014-03-20 Lone Fields, LLC
 furniture
 
-// futbol : 2013-09-20 undefined
+// futbol : 2013-09-20
 futbol
 
 // gal : 2013-11-07 Asociación puntoGAL
 gal
 
 // gallery : 2013-09-13 Sugar House, LLC
 gallery
 
@@ -7342,17 +7416,17 @@ guide
 guitars
 
 // guru : 2013-08-27 Pioneer Cypress, LLC
 guru
 
 // hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH
 hamburg
 
-// haus : 2013-12-05 undefined
+// haus : 2013-12-05
 haus
 
 // healthcare : 2014-06-12 Silver Glen, LLC
 healthcare
 
 // help : 2014-06-26 Uniregistry, Corp.
 help
 
@@ -7438,34 +7512,43 @@ ipiranga
 irish
 
 // ist : 2014-08-28 Istanbul Metropolitan Municipality
 ist
 
 // istanbul : 2014-08-28 Istanbul Metropolitan Municipality
 istanbul
 
+// itau : 2014-10-02 Itau Unibanco Holding S.A.
+itau
+
 // iwc : 2014-06-23 Richemont DNS Inc.
 iwc
 
 // java : 2014-06-19 Oracle Corporation
 java
 
 // jetzt : 2014-01-09 New TLD Company AB
 jetzt
 
 // joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
 joburg
 
+// jprs : 2014-09-18 Japan Registry Services Co., Ltd.
+jprs
+
 // juegos : 2014-03-20 Uniregistry, Corp.
 juegos
 
 // kaufen : 2013-11-07 United TLD Holdco Ltd.
 kaufen
 
+// kddi : 2014-09-12 KDDI CORPORATION
+kddi
+
 // kim : 2013-09-23 Afilias Limited
 kim
 
 // kitchen : 2013-09-20 Just Goodbye, LLC
 kitchen
 
 // kiwi : 2013-09-20 DOT KIWI LIMITED
 kiwi
@@ -7483,31 +7566,37 @@ kred
 lacaixa
 
 // land : 2013-09-10 Pine Moon, LLC
 land
 
 // latrobe : 2014-06-16 La Trobe University
 latrobe
 
-// lawyer : 2014-03-20 undefined
+// lawyer : 2014-03-20
 lawyer
 
 // lds : 2014-03-20 IRI Domain Management, LLC (\
 lds
 
 // lease : 2014-03-06 Victor Trail, LLC
 lease
 
 // leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc
 leclerc
 
 // lgbt : 2014-05-08 Afilias Limited
 lgbt
 
+// liaison : 2014-10-02 Liaison Technologies, Incorporated
+liaison
+
+// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+lidl
+
 // life : 2014-02-06 Trixy Oaks, LLC
 life
 
 // lighting : 2013-08-27 John McCook, LLC
 lighting
 
 // limited : 2014-03-06 Big Fest, LLC
 limited
@@ -7522,38 +7611,44 @@ link
 loans
 
 // london : 2013-11-14 Dot London Domains Limited
 london
 
 // lotto : 2014-04-10 Afilias Limited
 lotto
 
+// ltd : 2014-09-25 Over Corner, LLC
+ltd
+
 // ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA
 ltda
 
 // luxe : 2014-01-09 Top Level Domain Holdings Limited
 luxe
 
 // luxury : 2013-10-17 Luxury Partners, LLC
 luxury
 
 // madrid : 2014-05-01 Comunidad de Madrid
 madrid
 
+// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF)
+maif
+
 // maison : 2013-12-05 Victor Frostbite, LLC
 maison
 
 // management : 2013-11-07 John Goodbye, LLC
 management
 
 // mango : 2013-10-24 PUNTO FA S.L.
 mango
 
-// market : 2014-03-06 undefined
+// market : 2014-03-06
 market
 
 // marketing : 2013-11-07 Fern Pass, LLC
 marketing
 
 // media : 2014-03-06 Grand Glen, LLC
 media
 
@@ -7585,17 +7680,17 @@ moe
 monash
 
 // montblanc : 2014-06-23 Richemont DNS Inc.
 montblanc
 
 // mormon : 2013-12-05 IRI Domain Management, LLC (\
 mormon
 
-// mortgage : 2014-03-20 undefined
+// mortgage : 2014-03-20
 mortgage
 
 // moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
 moscow
 
 // motorcycles : 2014-01-09 DERMotorcycles, LLC
 motorcycles
 
@@ -7630,26 +7725,32 @@ ngo
 nhk
 
 // ninja : 2013-11-07 United TLD Holdco Ltd.
 ninja
 
 // nissan : 2014-03-27 NISSAN MOTOR CO., LTD.
 nissan
 
+// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+nowruz
+
 // nra : 2014-05-22 NRA Holdings Company, INC.
 nra
 
 // nrw : 2013-11-21 Minds + Machines GmbH
 nrw
 
 // nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications
 nyc
 
-// okinawa : 2013-12-05 BusinessRalliart inc.
+// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA
+obi
+
+// okinawa : 2013-12-05 BusinessRalliart Inc.
 okinawa
 
 // ong : 2014-03-06 Public Interest Registry
 ong
 
 // onl : 2013-09-16 I-Registry Ltd.
 onl
 
@@ -7657,31 +7758,40 @@ onl
 ooo
 
 // oracle : 2014-06-19 Oracle Corporation
 oracle
 
 // organic : 2014-03-27 Afilias Limited
 organic
 
+// osaka : 2014-09-04 Interlink Co., Ltd.
+osaka
+
 // otsuka : 2013-10-11 Otsuka Holdings Co., Ltd.
 otsuka
 
 // ovh : 2014-01-16 OVH SAS
 ovh
 
 // paris : 2014-01-30 City of Paris
 paris
 
+// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+pars
+
 // partners : 2013-12-05 Magic Glen, LLC
 partners
 
 // parts : 2013-12-05 Sea Goodbye, LLC
 parts
 
+// party : 2014-09-11 Blue Sky Registry Limited
+party
+
 // pharmacy : 2014-06-19 National Association of Boards of Pharmacy
 pharmacy
 
 // photo : 2013-11-14 Uniregistry, Corp.
 photo
 
 // photography : 2013-09-20 Sugar Glen, LLC
 photography
@@ -7762,16 +7872,19 @@ red
 rehab
 
 // reise : 2014-03-13 dotreise GmbH
 reise
 
 // reisen : 2014-03-06 New Cypress, LLC
 reisen
 
+// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc.
+reit
+
 // ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd.
 ren
 
 // rentals : 2013-12-05 Big Hollow,LLC
 rentals
 
 // repair : 2013-11-07 Lone Sunset, LLC
 repair
@@ -7783,41 +7896,41 @@ report
 republican
 
 // rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
 rest
 
 // restaurant : 2014-07-03 Snow Avenue, LLC
 restaurant
 
-// reviews : 2013-09-13 undefined
+// reviews : 2013-09-13
 reviews
 
 // rich : 2013-11-21 I-Registry Ltd.
 rich
 
 // rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO
 rio
 
 // rip : 2014-07-10 United TLD Holdco Ltd.
 rip
 
-// rocks : 2013-11-14 undefined
+// rocks : 2013-11-14
 rocks
 
 // rodeo : 2013-12-19 Top Level Domain Holdings Limited
 rodeo
 
 // rsvp : 2014-05-08 Charleston Road Registry Inc.
 rsvp
 
 // ruhr : 2013-10-02 regiodot GmbH & Co. KG
 ruhr
 
-// ryukyu : 2014-01-09 BusinessRalliart inc.
+// ryukyu : 2014-01-09 BusinessRalliart Inc.
 ryukyu
 
 // saarland : 2013-12-12 dotSaarland GmbH
 saarland
 
 // samsung : 2014-04-03 SAMSUNG SDS CO., LTD
 samsung
 
@@ -7837,16 +7950,22 @@ scb
 schmidt
 
 // scholarships : 2014-04-24 Scholarships.com, LLC
 scholarships
 
 // schule : 2014-03-06 Outer Moon, LLC
 schule
 
+// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+schwarz
+
+// science : 2014-09-11 dot Science Limited
+science
+
 // scot : 2014-01-23 Dot Scot Registry Limited
 scot
 
 // seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal)
 seat
 
 // services : 2014-02-27 Fox Castle, LLC
 services
@@ -7855,16 +7974,19 @@ services
 sew
 
 // sexy : 2013-09-11 Uniregistry, Corp.
 sexy
 
 // sharp : 2014-05-01 Sharp Corporation
 sharp
 
+// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+shia
+
 // shiksha : 2013-11-14 Afilias Limited
 shiksha
 
 // shoes : 2013-10-02 Binky Galley, LLC
 shoes
 
 // shriram : 2014-01-23 Shriram Capital Ltd.
 shriram
@@ -7873,17 +7995,17 @@ shriram
 singles
 
 // sky : 2014-06-19 Sky IP International Ltd, a company incorporated in England and Wales, operating via its registered Swiss branch
 sky
 
 // social : 2013-11-07 United TLD Holdco Ltd.
 social
 
-// software : 2014-03-20 undefined
+// software : 2014-03-20
 software
 
 // sohu : 2013-12-19 Sohu.com Limited
 sohu
 
 // solar : 2013-11-07 Ruby Town, LLC
 solar
 
@@ -7912,31 +8034,37 @@ support
 surf
 
 // surgery : 2014-03-20 Tin Avenue, LLC
 surgery
 
 // suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION
 suzuki
 
+// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet
+sydney
+
 // systems : 2013-11-07 Dash Cypress, LLC
 systems
 
 // taipei : 2014-07-10 Taipei City Government
 taipei
 
 // tatar : 2014-04-24 Limited Liability Company \
 tatar
 
 // tattoo : 2013-08-30 Uniregistry, Corp.
 tattoo
 
 // tax : 2014-03-20 Storm Orchard, LLC
 tax
 
+// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+tci
+
 // technology : 2013-09-13 Auburn Falls
 technology
 
 // temasek : 2014-08-07 Temasek Holdings (Private) Limited
 temasek
 
 // tienda : 2013-11-14 Victor Manor, LLC
 tienda
@@ -7993,28 +8121,37 @@ vacations
 vegas
 
 // ventures : 2013-08-27 Binky Lake, LLC
 ventures
 
 // versicherung : 2014-03-20 dotversicherung-registry GmbH
 versicherung
 
-// vet : 2014-03-06 undefined
+// vet : 2014-03-06
 vet
 
 // viajes : 2013-10-17 Black Madison, LLC
 viajes
 
 // villas : 2013-12-05 New Sky, LLC
 villas
 
+// virgin : 2014-09-25 Virgin Enterprises Limited
+virgin
+
 // vision : 2013-12-05 Koko Station, LLC
 vision
 
+// vista : 2014-09-18 Vistaprint Limited
+vista
+
+// vistaprint : 2014-09-18 Vistaprint Limited
+vistaprint
+
 // vlaanderen : 2014-02-06 DNS.be vzw
 vlaanderen
 
 // vodka : 2013-12-19 Top Level Domain Holdings Limited
 vodka
 
 // vote : 2013-11-21 Monolith Registry LLC
 vote
@@ -8167,16 +8304,19 @@ wtf
 网络
 
 // xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd
 手机
 
 // xn--mgbab2bd : 2013-10-31 CORE Association
 بازار
 
+// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+همراه
+
 // xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd.
 政府
 
 // xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd.
 شبكة
 
 // xn--nqv7f : 2013-11-14 Public Interest Registry
 机构
@@ -8234,17 +8374,17 @@ yokohama
 
 // youtube : 2014-05-01 Charleston Road Registry Inc.
 youtube
 
 // zip : 2014-05-08 Charleston Road Registry Inc.
 zip
 
 // zone : 2013-11-14 Outer Falls, LLC
-zone 
+zone
 
 // ===END ICANN DOMAINS===
 // ===BEGIN PRIVATE DOMAINS===
 
 // Amazon CloudFront : https://aws.amazon.com/cloudfront/
 // Submitted by Donavan Miller <donavanm@amazon.com> 2013-03-22
 cloudfront.net
 
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -298,17 +298,17 @@ NeckoChild::AllocPChannelDiverterChild(c
 bool
 NeckoChild::DeallocPChannelDiverterChild(PChannelDiverterChild* child)
 {
   delete static_cast<ChannelDiverterChild*>(child);
   return true;
 }
 
 bool
-NeckoChild::RecvAsyncAuthPromptForNestedFrame(const uint64_t& aNestedFrameId,
+NeckoChild::RecvAsyncAuthPromptForNestedFrame(const TabId& aNestedFrameId,
                                               const nsCString& aUri,
                                               const nsString& aRealm,
                                               const uint64_t& aCallbackId)
 {
   auto iter = dom::TabChild::NestedTabChildMap().find(aNestedFrameId);
   if (iter == dom::TabChild::NestedTabChildMap().end()) {
     MOZ_CRASH();
     return false;
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -66,17 +66,17 @@ protected:
   virtual PRtspChannelChild*
     AllocPRtspChannelChild(const RtspChannelConnectArgs& aArgs)
                            MOZ_OVERRIDE;
   virtual bool DeallocPRtspChannelChild(PRtspChannelChild*) MOZ_OVERRIDE;
   virtual PChannelDiverterChild*
   AllocPChannelDiverterChild(const ChannelDiverterArgs& channel) MOZ_OVERRIDE;
   virtual bool
   DeallocPChannelDiverterChild(PChannelDiverterChild* actor) MOZ_OVERRIDE;
-  virtual bool RecvAsyncAuthPromptForNestedFrame(const uint64_t& aNestedFrameId,
+  virtual bool RecvAsyncAuthPromptForNestedFrame(const TabId& aNestedFrameId,
                                                  const nsCString& aUri,
                                                  const nsString& aRealm,
                                                  const uint64_t& aCallbackId) MOZ_OVERRIDE;
   virtual bool RecvAppOfflineStatus(const uint32_t& aId, const bool& aOffline) MOZ_OVERRIDE;
 };
 
 /**
  * Reference to the PNecko Child protocol.
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -183,19 +183,19 @@ NeckoParent::CreateChannelLoadContext(co
         dom::Element* topFrameElement = nullptr;
         if (tabParent) {
           topFrameElement = tabParent->GetOwnerElement();
         }
         aResult = new LoadContext(aSerialized, topFrameElement,
                                   appId, inBrowser);
         break;
       }
-      case PBrowserOrId::Tuint64_t:
+      case PBrowserOrId::TTabId:
       {
-        aResult = new LoadContext(aSerialized, aBrowser.get_uint64_t(),
+        aResult = new LoadContext(aSerialized, aBrowser.get_TabId(),
                                   appId, inBrowser);
         break;
       }
       default:
         MOZ_CRASH();
     }
   }
 
@@ -728,17 +728,17 @@ CallbackMap()
   static std::map<uint64_t, nsCOMPtr<nsIAuthPromptCallback> > sCallbackMap;
   return sCallbackMap;
 }
 } // anonymous namespace
 
 NS_IMPL_ISUPPORTS(NeckoParent::NestedFrameAuthPrompt, nsIAuthPrompt2)
 
 NeckoParent::NestedFrameAuthPrompt::NestedFrameAuthPrompt(PNeckoParent* aParent,
-                                                          uint64_t aNestedFrameId)
+                                                          TabId aNestedFrameId)
   : mNeckoParent(aParent)
   , mNestedFrameId(aNestedFrameId)
 {}
 
 NS_IMETHODIMP
 NeckoParent::NestedFrameAuthPrompt::AsyncPromptAuth(
   nsIChannel* aChannel, nsIAuthPromptCallback* callback,
   nsISupports*, uint32_t,
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -73,17 +73,17 @@ public:
    */
   class NestedFrameAuthPrompt MOZ_FINAL : public nsIAuthPrompt2
   {
     ~NestedFrameAuthPrompt() {}
 
   public:
     NS_DECL_ISUPPORTS
 
-    NestedFrameAuthPrompt(PNeckoParent* aParent, uint64_t aNestedFrameId);
+    NestedFrameAuthPrompt(PNeckoParent* aParent, TabId aNestedFrameId);
 
     NS_IMETHOD PromptAuth(nsIChannel*, uint32_t, nsIAuthInformation*, bool*)
     {
       return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     NS_IMETHOD AsyncPromptAuth(nsIChannel* aChannel, nsIAuthPromptCallback* callback,
                                nsISupports*, uint32_t,
@@ -93,17 +93,17 @@ public:
                                 nsIAuthPromptCallback*, nsISupports*,
                                 uint32_t, nsIAuthInformation*, nsICancelable**)
     {
       return NS_ERROR_NOT_IMPLEMENTED;
     }
 
   protected:
     PNeckoParent* mNeckoParent;
-    uint64_t mNestedFrameId;
+    TabId mNestedFrameId;
   };
 
 protected:
   virtual PHttpChannelParent*
     AllocPHttpChannelParent(const PBrowserOrId&, const SerializedLoadContext&,
                             const HttpChannelCreationArgs& aOpenArgs) MOZ_OVERRIDE;
   virtual bool
     RecvPHttpChannelConstructor(
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -21,28 +21,24 @@ include protocol PChannelDiverter;
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet;
 
 include protocol PRtspController;
 include protocol PRtspChannel;
 include URIParams;
 include InputStreamParams;
 include NeckoChannelParams;
-
+include PBrowserOrId;
 
 using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 namespace net {
 
-union PBrowserOrId {
-  nullable PBrowser;
-  uint64_t;
-};
-
 //-------------------------------------------------------------------
 sync protocol PNecko
 {
   manager PContent;
   manages PHttpChannel;
   manages PCookieService;
   manages PWyciwygChannel;
   manages PFTPChannel;
@@ -93,17 +89,17 @@ parent:
   OnAuthCancelled(uint64_t callbackId, bool userCancel);
 
 child:
   /*
    * Bring up the http auth prompt for a nested remote mozbrowser.
    * NestedFrameId is the id corresponding to the PBrowser.  It is the same id
    * that was passed to the PBrowserOrId param in to the PHttpChannel constructor
    */
-  AsyncAuthPromptForNestedFrame(uint64_t nestedFrameId, nsCString uri,
+  AsyncAuthPromptForNestedFrame(TabId nestedFrameId, nsCString uri,
                                 nsString realm, uint64_t callbackId);
   // Notifies child that a given app is now offline (or online)
   AppOfflineStatus(uint32_t appId, bool offline);
 
 both:
   // Actually we need PTCPSocket() for parent. But ipdl disallows us having different
   // signatures on parent and child. So when constructing the parent side object, we just 
   // leave host/port unused.
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1051,17 +1051,17 @@ HttpChannelChild::ConnectParent(uint32_t
   AddIPDLReference();
 
   HttpChannelConnectArgs connectArgs(id);
   PBrowserOrId browser;
   if (!tabChild ||
       static_cast<ContentChild*>(gNeckoChild->Manager()) == tabChild->Manager()) {
     browser = tabChild;
   } else {
-    browser = TabChild::GetTabChildId(tabChild);
+    browser = tabChild->GetTabId();
   }
   if (!gNeckoChild->
         SendPHttpChannelConstructor(this, browser,
                                     IPC::SerializedLoadContext(this),
                                     connectArgs)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -1521,17 +1521,17 @@ HttpChannelChild::ContinueAsyncOpen()
   // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
   AddIPDLReference();
 
   PBrowserOrId browser;
   if (!tabChild ||
       static_cast<ContentChild*>(gNeckoChild->Manager()) == tabChild->Manager()) {
     browser = tabChild;
   } else {
-    browser = TabChild::GetTabChildId(tabChild);
+    browser = tabChild->GetTabId();
   }
   gNeckoChild->SendPHttpChannelConstructor(this, browser,
                                            IPC::SerializedLoadContext(this),
                                            openArgs);
 
   if (fdSet) {
     FileDescriptorSetChild* fdSetActor =
       static_cast<FileDescriptorSetChild*>(fdSet);
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -62,17 +62,17 @@ HttpChannelParent::HttpChannelParent(con
     do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http");
 
   MOZ_ASSERT(gHttpHandler);
   mHttpHandler = gHttpHandler;
 
   if (iframeEmbedding.type() == PBrowserOrId::TPBrowserParent) {
     mTabParent = static_cast<dom::TabParent*>(iframeEmbedding.get_PBrowserParent());
   } else {
-    mNestedFrameId = iframeEmbedding.get_uint64_t();
+    mNestedFrameId = iframeEmbedding.get_TabId();
   }
 
   mObserver = new OfflineObserver(this);
 }
 
 HttpChannelParent::~HttpChannelParent()
 {
   if (mObserver) {
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -14,30 +14,31 @@
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/net/NeckoParent.h"
 #include "OfflineObserver.h"
 #include "nsIObserver.h"
 #include "nsIParentRedirectingChannel.h"
 #include "nsIProgressEventSink.h"
 #include "nsHttpChannel.h"
 #include "nsIAuthPromptProvider.h"
+#include "mozilla/dom/ipc/IdType.h"
 
 class nsICacheEntry;
 class nsIAssociatedContentSecurity;
 
 namespace mozilla {
 
 namespace dom{
 class TabParent;
+class PBrowserOrId;
 }
 
 namespace net {
 
 class HttpChannelParentListener;
-class PBrowserOrId;
 
 class HttpChannelParent : public PHttpChannelParent
                         , public nsIParentRedirectingChannel
                         , public nsIProgressEventSink
                         , public nsIInterfaceRequestor
                         , public ADivertableParentChannel
                         , public nsIAuthPromptProvider
                         , public DisconnectableParent
@@ -49,17 +50,17 @@ public:
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIPARENTCHANNEL
   NS_DECL_NSIPARENTREDIRECTINGCHANNEL
   NS_DECL_NSIPROGRESSEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIAUTHPROMPTPROVIDER
 
-  HttpChannelParent(const PBrowserOrId& iframeEmbedding,
+  HttpChannelParent(const dom::PBrowserOrId& iframeEmbedding,
                     nsILoadContext* aLoadContext,
                     PBOverrideStatus aStatus);
 
   bool Init(const HttpChannelCreationArgs& aOpenArgs);
 
   // ADivertableParentChannel functions.
   void DivertTo(nsIStreamListener *aListener) MOZ_OVERRIDE;
   nsresult SuspendForDiversion() MOZ_OVERRIDE;
@@ -180,15 +181,15 @@ private:
   // received from the child channel.
   bool mDivertingFromChild;
 
   // Set if OnStart|StopRequest was called during a diversion from the child.
   bool mDivertedOnStartRequest;
 
   bool mSuspendedForDiversion;
 
-  uint64_t mNestedFrameId;
+  dom::TabId mNestedFrameId;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/system/mac/nsNetworkLinkService.h
+++ b/netwerk/system/mac/nsNetworkLinkService.h
@@ -4,16 +4,17 @@
 
 #ifndef NSNETWORKLINKSERVICEMAC_H_
 #define NSNETWORKLINKSERVICEMAC_H_
 
 #include "nsINetworkLinkService.h"
 #include "nsIObserver.h"
 
 #include <SystemConfiguration/SCNetworkReachability.h>
+#include <SystemConfiguration/SystemConfiguration.h>
 
 class nsNetworkLinkService : public nsINetworkLinkService,
                              public nsIObserver
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSINETWORKLINKSERVICE
     NS_DECL_NSIOBSERVER
@@ -25,19 +26,27 @@ public:
 
 protected:
     virtual ~nsNetworkLinkService();
 
 private:
     bool mLinkUp;
     bool mStatusKnown;
 
+    // Toggles allowing the sending of network-changed event.
+    bool mAllowChangedEvent;
+
     SCNetworkReachabilityRef mReachability;
     CFRunLoopRef mCFRunLoop;
+    CFRunLoopSourceRef mRunLoopSource;
+    SCDynamicStoreRef mStoreRef;
 
     void UpdateReachability();
-    void SendEvent();
+    void SendEvent(bool aNetworkChanged);
     static void ReachabilityChanged(SCNetworkReachabilityRef target,
                                     SCNetworkConnectionFlags flags,
                                     void *info);
+    static void IPConfigChanged(SCDynamicStoreRef store,
+                                CFArrayRef changedKeys,
+                                void *info);
 };
 
 #endif /* NSNETWORKLINKSERVICEMAC_H_ */
--- a/netwerk/system/mac/nsNetworkLinkService.mm
+++ b/netwerk/system/mac/nsNetworkLinkService.mm
@@ -4,29 +4,69 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsNetworkLinkService.h"
 #include "nsCOMPtr.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsCRT.h"
+#include "mozilla/Preferences.h"
 
 #import <Cocoa/Cocoa.h>
 #import <netinet/in.h>
 
+#define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed"
+
+using namespace mozilla;
+
+// If non-successful, extract the error code and return it.  This
+// error code dance is inspired by
+// http://developer.apple.com/technotes/tn/tn1145.html
+static OSStatus getErrorCodeBool(Boolean success)
+{
+    OSStatus err = noErr;
+    if (!success) {
+        int scErr = ::SCError();
+        if (scErr == kSCStatusOK) {
+            scErr = kSCStatusFailed;
+        }
+        err = scErr;
+    }
+    return err;
+}
+
+// If given a NULL pointer, return the error code.
+static OSStatus getErrorCodePtr(const void *value)
+{
+    return getErrorCodeBool(value != NULL);
+}
+
+// Convenience function to allow NULL input.
+static void CFReleaseSafe(CFTypeRef cf)
+{
+    if (cf) {
+        // "If cf is NULL, this will cause a runtime error and your
+        // application will crash." / Apple docs
+        ::CFRelease(cf);
+    }
+}
+
 NS_IMPL_ISUPPORTS(nsNetworkLinkService,
                   nsINetworkLinkService,
                   nsIObserver)
 
 nsNetworkLinkService::nsNetworkLinkService()
     : mLinkUp(true)
     , mStatusKnown(false)
-    , mReachability(NULL)
-    , mCFRunLoop(NULL)
+    , mAllowChangedEvent(true)
+    , mReachability(nullptr)
+    , mCFRunLoop(nullptr)
+    , mRunLoopSource(nullptr)
+    , mStoreRef(nullptr)
 {
 }
 
 nsNetworkLinkService::~nsNetworkLinkService()
 {
 }
 
 NS_IMETHODIMP
@@ -60,28 +100,42 @@ nsNetworkLinkService::Observe(nsISupport
 {
     if (!strcmp(topic, "xpcom-shutdown")) {
         Shutdown();
     }
 
     return NS_OK;
 }
 
+/* static */
+void
+nsNetworkLinkService::IPConfigChanged(SCDynamicStoreRef aStoreREf,
+                                      CFArrayRef aChangedKeys,
+                                      void *aInfo)
+{
+    nsNetworkLinkService *service =
+        static_cast<nsNetworkLinkService*>(aInfo);
+    service->SendEvent(true);
+}
+
 nsresult
 nsNetworkLinkService::Init(void)
 {
     nsresult rv;
 
     nsCOMPtr<nsIObserverService> observerService =
         do_GetService("@mozilla.org/observer-service;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = observerService->AddObserver(this, "xpcom-shutdown", false);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    Preferences::AddBoolVarCache(&mAllowChangedEvent,
+                                 NETWORK_NOTIFY_CHANGED_PREF, true);
+
     // If the network reachability API can reach 0.0.0.0 without
     // requiring a connection, there is a network interface available.
     struct sockaddr_in addr;
     bzero(&addr, sizeof(addr));
     addr.sin_len = sizeof(addr);
     addr.sin_family = AF_INET;
     mReachability =
         ::SCNetworkReachabilityCreateWithAddress(NULL,
@@ -95,27 +149,90 @@ nsNetworkLinkService::Init(void)
                                             ReachabilityChanged,
                                             &context)) {
         NS_WARNING("SCNetworkReachabilitySetCallback failed.");
         ::CFRelease(mReachability);
         mReachability = NULL;
         return NS_ERROR_NOT_AVAILABLE;
     }
 
+    SCDynamicStoreContext storeContext = {0, this, NULL, NULL, NULL};
+    mStoreRef =
+        ::SCDynamicStoreCreate(NULL,
+                               CFSTR("AddIPAddressListChangeCallbackSCF"),
+                               IPConfigChanged, &storeContext);
+
+    CFStringRef patterns[2] = {NULL, NULL};
+    OSStatus err = getErrorCodePtr(mStoreRef);
+    if (err == noErr) {
+        // This pattern is "State:/Network/Service/[^/]+/IPv4".
+        patterns[0] =
+            ::SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                          kSCDynamicStoreDomainState,
+                                                          kSCCompAnyRegex,
+                                                          kSCEntNetIPv4);
+        err = getErrorCodePtr(patterns[0]);
+        if (err == noErr) {
+            // This pattern is "State:/Network/Service/[^/]+/IPv6".
+            patterns[1] =
+                ::SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+                                                              kSCDynamicStoreDomainState,
+                                                              kSCCompAnyRegex,
+                                                              kSCEntNetIPv6);
+            err = getErrorCodePtr(patterns[1]);
+        }
+    }
+
+    CFArrayRef patternList = NULL;
+    // Create a pattern list containing just one pattern,
+    // then tell SCF that we want to watch changes in keys
+    // that match that pattern list, then create our run loop
+    // source.
+    if (err == noErr) {
+        patternList = ::CFArrayCreate(NULL, (const void **) patterns,
+                                      2, &kCFTypeArrayCallBacks);
+        if (!patternList) {
+            err = -1;
+        }
+    }
+    if (err == noErr) {
+        err =
+            getErrorCodeBool(::SCDynamicStoreSetNotificationKeys(mStoreRef,
+                                                                 NULL,
+                                                                 patternList));
+    }
+
+    if (err == noErr) {
+        mRunLoopSource =
+            ::SCDynamicStoreCreateRunLoopSource(NULL, mStoreRef, 0);
+        err = getErrorCodePtr(mRunLoopSource);
+    }
+
+    CFReleaseSafe(patterns[0]);
+    CFReleaseSafe(patterns[1]);
+    CFReleaseSafe(patternList);
+
+    if (err != noErr) {
+        CFReleaseSafe(mStoreRef);
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+
     // Get the current run loop.  This service is initialized at startup,
     // so we shouldn't run in to any problems with modal dialog run loops.
     mCFRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
     if (!mCFRunLoop) {
         NS_WARNING("Could not get current run loop.");
         ::CFRelease(mReachability);
         mReachability = NULL;
         return NS_ERROR_NOT_AVAILABLE;
     }
     ::CFRetain(mCFRunLoop);
 
+    ::CFRunLoopAddSource(mCFRunLoop, mRunLoopSource, kCFRunLoopDefaultMode);
+
     if (!::SCNetworkReachabilityScheduleWithRunLoop(mReachability, mCFRunLoop,
                                                     kCFRunLoopDefaultMode)) {
         NS_WARNING("SCNetworkReachabilityScheduleWIthRunLoop failed.");
         ::CFRelease(mReachability);
         mReachability = NULL;
         ::CFRelease(mCFRunLoop);
         mCFRunLoop = NULL;
         return NS_ERROR_NOT_AVAILABLE;
@@ -130,21 +247,29 @@ nsresult
 nsNetworkLinkService::Shutdown()
 {
     if (!::SCNetworkReachabilityUnscheduleFromRunLoop(mReachability,
                                                       mCFRunLoop,
                                                       kCFRunLoopDefaultMode)) {
         NS_WARNING("SCNetworkReachabilityUnscheduleFromRunLoop failed.");
     }
 
+    CFRunLoopRemoveSource(mCFRunLoop, mRunLoopSource, kCFRunLoopDefaultMode);
+
     ::CFRelease(mReachability);
-    mReachability = NULL;
+    mReachability = nullptr;
 
     ::CFRelease(mCFRunLoop);
-    mCFRunLoop = NULL;
+    mCFRunLoop = nullptr;
+
+    ::CFRelease(mStoreRef);
+    mStoreRef = nullptr;
+
+    ::CFRelease(mRunLoopSource);
+    mRunLoopSource = nullptr;
 
     return NS_OK;
 }
 
 void
 nsNetworkLinkService::UpdateReachability()
 {
     if (!mReachability) {
@@ -160,39 +285,45 @@ nsNetworkLinkService::UpdateReachability
     bool reachable = (flags & kSCNetworkFlagsReachable) != 0;
     bool needsConnection = (flags & kSCNetworkFlagsConnectionRequired) != 0;
 
     mLinkUp = (reachable && !needsConnection);
     mStatusKnown = true;
 }
 
 void
-nsNetworkLinkService::SendEvent()
+nsNetworkLinkService::SendEvent(bool aNetworkChanged)
 {
     nsCOMPtr<nsIObserverService> observerService =
         do_GetService("@mozilla.org/observer-service;1");
     if (!observerService)
         return;
 
     const char *event;
-    if (!mStatusKnown)
+    if (aNetworkChanged) {
+        if (!mAllowChangedEvent) {
+            return;
+        }
+        event = NS_NETWORK_LINK_DATA_CHANGED;
+    } else if (!mStatusKnown) {
         event = NS_NETWORK_LINK_DATA_UNKNOWN;
-    else
+    } else {
         event = mLinkUp ? NS_NETWORK_LINK_DATA_UP
-                        : NS_NETWORK_LINK_DATA_DOWN;
+            : NS_NETWORK_LINK_DATA_DOWN;
+    }
 
     observerService->NotifyObservers(static_cast<nsINetworkLinkService*>(this),
                                      NS_NETWORK_LINK_TOPIC,
                                      NS_ConvertASCIItoUTF16(event).get());
 }
 
 /* static */
 void
 nsNetworkLinkService::ReachabilityChanged(SCNetworkReachabilityRef target,
                                           SCNetworkConnectionFlags flags,
                                           void *info)
 {
     nsNetworkLinkService *service =
         static_cast<nsNetworkLinkService*>(info);
 
     service->UpdateReachability();
-    service->SendEvent();
+    service->SendEvent(false);
 }
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -861,43 +861,55 @@ nsSSLIOLayerHelpers::rememberTolerantAtV
     entry.intoleranceReason = 0;
   }
 
   entry.AssertInvariant();
 
   mTLSIntoleranceInfo.Put(key, entry);
 }
 
+void nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName,
+                                            int16_t port)
+{
+  nsCString key;
+  getSiteKey(hostName, port, key);
+
+  MutexAutoLock lock(mutex);
+
+  IntoleranceEntry entry;
+  if (mTLSIntoleranceInfo.Get(key, &entry)) {
+    entry.AssertInvariant();
+
+    entry.intolerant = 0;
+    entry.intoleranceReason = 0;
+
+    entry.AssertInvariant();
+    mTLSIntoleranceInfo.Put(key, entry);
+  }
+}
+
 // returns true if we should retry the handshake
 bool
 nsSSLIOLayerHelpers::rememberIntolerantAtVersion(const nsACString& hostName,
                                                  int16_t port,
                                                  uint16_t minVersion,
                                                  uint16_t intolerant,
                                                  PRErrorCode intoleranceReason)
 {
+  if (intolerant <= minVersion || intolerant <= mVersionFallbackLimit) {
+    // We can't fall back any further. Assume that intolerance isn't the issue.
+    forgetIntolerance(hostName, port);
+    return false;
+  }
+
   nsCString key;
   getSiteKey(hostName, port, key);
 
   MutexAutoLock lock(mutex);
 
-  if (intolerant <= minVersion || intolerant <= mVersionFallbackLimit) {
-    // We can't fall back any further. Assume that intolerance isn't the issue.
-    IntoleranceEntry entry;
-    if (mTLSIntoleranceInfo.Get(key, &entry)) {
-      entry.AssertInvariant();
-      entry.intolerant = 0;
-      entry.intoleranceReason = 0;
-      entry.AssertInvariant();
-      mTLSIntoleranceInfo.Put(key, entry);
-    }
-
-    return false;
-  }
-
   IntoleranceEntry entry;
   if (mTLSIntoleranceInfo.Get(key, &entry)) {
     entry.AssertInvariant();
     if (intolerant <= entry.tolerant) {
       // We already know the server is tolerant at an equal or higher version.
       return false;
     }
     if ((entry.intolerant != 0 && intolerant >= entry.intolerant)) {
@@ -1137,32 +1149,29 @@ retryDueToTLSIntolerance(PRErrorCode err
   // This function is supposed to decide which error codes should
   // be used to conclude server is TLS intolerant.
   // Note this only happens during the initial SSL handshake.
 
   SSLVersionRange range = socketInfo->GetTLSVersionRange();
 
   if (err == SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT) {
     // This is a clear signal that we've fallen back too many versions.  Treat
-    // this as a hard failure now, but also mark the next higher version as
-    // being tolerant so that later attempts don't use this version (i.e.,
-    // range.max), which makes the error unrecoverable without a full restart.
+    // this as a hard failure, but forget any intolerance so that later attempts
+    // don't use this version (i.e., range.max) and trigger the error again.
 
     // First, track the original cause of the version fallback.  This uses the
     // same buckets as the telemetry below, except that bucket 0 will include
     // all cases where there wasn't an original reason.
     PRErrorCode originalReason = socketInfo->SharedState().IOLayerHelpers()
       .getIntoleranceReason(socketInfo->GetHostName(), socketInfo->GetPort());
     Telemetry::Accumulate(Telemetry::SSL_VERSION_FALLBACK_INAPPROPRIATE,
                           tlsIntoleranceTelemetryBucket(originalReason));
 
     socketInfo->SharedState().IOLayerHelpers()
-      .rememberTolerantAtVersion(socketInfo->GetHostName(),
-                                 socketInfo->GetPort(),
-                                 range.max + 1);
+      .forgetIntolerance(socketInfo->GetHostName(), socketInfo->GetPort());
 
     return false;
   }
 
   // When not using a proxy we'll see a connection reset error.
   // When using a proxy, we'll see an end of file error.
   // In addition check for some error codes where it is reasonable
   // to retry without TLS.
--- a/security/manager/ssl/src/nsNSSIOLayer.h
+++ b/security/manager/ssl/src/nsNSSIOLayer.h
@@ -211,16 +211,17 @@ private:
   };
   nsDataHashtable<nsCStringHashKey, IntoleranceEntry> mTLSIntoleranceInfo;
 public:
   void rememberTolerantAtVersion(const nsACString& hostname, int16_t port,
                                  uint16_t tolerant);
   bool rememberIntolerantAtVersion(const nsACString& hostname, int16_t port,
                                    uint16_t intolerant, uint16_t minVersion,
                                    PRErrorCode intoleranceReason);
+  void forgetIntolerance(const nsACString& hostname, int16_t port);
   void adjustForTLSIntolerance(const nsACString& hostname, int16_t port,
                                /*in/out*/ SSLVersionRange& range);
   PRErrorCode getIntoleranceReason(const nsACString& hostname, int16_t port);
 
   void setRenegoUnrestrictedSites(const nsCString& str);
   bool isRenegoUnrestrictedSite(const nsCString& str);
   void clearStoredData();
   void loadVersionFallbackLimit();
--- a/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
+++ b/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
@@ -236,8 +236,70 @@ TEST_F(TLSIntoleranceTest, Test_Intolera
                                       SSL_LIBRARY_VERSION_TLS_1_2,
                                       SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
   ASSERT_EQ(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT,
             helpers.getIntoleranceReason(HOST, 1));
 
   helpers.rememberTolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_2);
   ASSERT_EQ(0, helpers.getIntoleranceReason(HOST, 1));
 }
+
+TEST_F(TLSIntoleranceTest, TLS_Forget_Intolerance)
+{
+  {
+    ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+                                                    SSL_LIBRARY_VERSION_3_0,
+                                                    SSL_LIBRARY_VERSION_TLS_1_2,
+                                                    0));
+
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+  }
+
+  {
+    helpers.forgetIntolerance(HOST, PORT);
+
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+  }
+}
+
+TEST_F(TLSIntoleranceTest, TLS_Dont_Forget_Tolerance)
+{
+  {
+    helpers.rememberTolerantAtVersion(HOST, 1, SSL_LIBRARY_VERSION_TLS_1_1);
+
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+  }
+
+  {
+    ASSERT_TRUE(helpers.rememberIntolerantAtVersion(HOST, PORT,
+                                                    SSL_LIBRARY_VERSION_3_0,
+                                                    SSL_LIBRARY_VERSION_TLS_1_2,
+                                                    0));
+
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_1, range.max);
+  }
+
+  {
+    helpers.forgetIntolerance(HOST, PORT);
+
+    SSLVersionRange range = { SSL_LIBRARY_VERSION_3_0,
+                              SSL_LIBRARY_VERSION_TLS_1_2 };
+    helpers.adjustForTLSIntolerance(HOST, PORT, range);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
+    ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
+  }
+}
--- a/testing/mochitest/chunkifyTests.js
+++ b/testing/mochitest/chunkifyTests.js
@@ -10,17 +10,17 @@ function chunkifyTests(tests, totalChunk
 
   // We want to split the tests up into chunks according to which directory
   // they're in
   if (chunkByDir) {
     chunkByDir = parseInt(chunkByDir);
     var tests_by_dir = {};
     var test_dirs = []
     for (var i = 0; i < tests.length; ++i) {
-      if ('test' in tests[i]) {
+      if ((tests[i] instanceof Object) && ('test' in tests[i])) {
         var test_path = tests[i]['test']['url'];
       } else {
         var test_path = tests[i]['url'];
       }
       if (test_path[0] == '/') {
         test_path = test_path.substr(1);
       }
       // mochitest-chrome and mochitest-browser-chrome pass an array of chrome://
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -1826,16 +1826,25 @@ RENDER_AGAIN:
   }
   // The following widgets need to be RTL-aware
   else if (aWidgetType == NS_THEME_RESIZER ||
            aWidgetType == NS_THEME_DROPDOWN_BUTTON)
   {
     DrawThemeBGRTLAware(theme, hdc, part, state,
                         &widgetRect, &clipRect, IsFrameRTL(aFrame));
   }
+  else if (aWidgetType == NS_THEME_NUMBER_INPUT ||
+           aWidgetType == NS_THEME_TEXTFIELD ||
+           aWidgetType == NS_THEME_TEXTFIELD_MULTILINE) {
+    DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect);
+     if (state == TFS_EDITBORDER_DISABLED) {
+      InflateRect(&widgetRect, -1, -1);
+      ::FillRect(hdc, &widgetRect, reinterpret_cast<HBRUSH>(COLOR_BTNFACE+1));
+    }
+  }
   else if (aWidgetType == NS_THEME_PROGRESSBAR ||
            aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL) {
     // DrawThemeBackground renders each corner with a solid white pixel.
     // Restore these pixels to the underlying color. Tracks are rendered
     // using alpha recovery, so this makes the corners transparent.
     COLORREF color;
     color = GetPixel(hdc, widgetRect.left, widgetRect.top);
     DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect);
new file mode 100644
--- /dev/null
+++ b/xpcom/base/ErrorNames.cpp
@@ -0,0 +1,83 @@
+/* -*- 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/ArrayUtils.h"
+#include "mozilla/ErrorNames.h"
+#include "nsString.h"
+#include "prerror.h"
+
+namespace {
+
+struct ErrorEntry
+{
+  nsresult value;
+  const char * name;
+};
+
+#undef ERROR
+#define ERROR(key, val) {key, #key}
+
+const ErrorEntry errors[] = {
+  #include "ErrorList.h"
+};
+
+#undef ERROR
+
+} // unnamed namespace
+
+namespace mozilla {
+
+void
+GetErrorName(nsresult rv, nsACString& name)
+{
+  for (size_t i = 0; i < ArrayLength(errors); ++i) {
+    if (errors[i].value == rv) {
+      name.AssignASCII(errors[i].name);
+      return;
+    }
+  }
+
+  bool isSecurityError = NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_SECURITY;
+
+  // NS_ERROR_MODULE_SECURITY is the only module that is "allowed" to
+  // synthesize nsresult error codes that are not listed in ErrorList.h. (The
+  // NS_ERROR_MODULE_SECURITY error codes are synthesized from NSPR error
+  // codes.)
+  MOZ_ASSERT(isSecurityError);
+
+  name.AssignASCII(NS_SUCCEEDED(rv) ? "NS_ERROR_GENERATE_SUCCESS("
+                                    : "NS_ERROR_GENERATE_FAILURE(");
+
+  if (isSecurityError) {
+    name.AppendASCII("NS_ERROR_MODULE_SECURITY");
+  } else {
+    // This should never happen given the assertion above, so we don't bother
+    // trying to print a symbolic name for the module here.
+    name.AppendInt(NS_ERROR_GET_MODULE(rv));
+  }
+
+  name.AppendASCII(", ");
+
+  const char * nsprName = nullptr;
+  if (isSecurityError) {
+    // Invert the logic from NSSErrorsService::GetXPCOMFromNSSError
+    PRErrorCode nsprCode
+      = -1 * static_cast<PRErrorCode>(NS_ERROR_GET_CODE(rv));
+    nsprName = PR_ErrorToName(nsprCode);
+
+    // All NSPR error codes defined by NSPR or NSS should have a name mapping.
+    MOZ_ASSERT(nsprName);
+  }
+
+  if (nsprName) {
+    name.AppendASCII(nsprName);
+  } else {
+    name.AppendInt(NS_ERROR_GET_CODE(rv));
+  }
+
+  name.AppendASCII(")");
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/xpcom/base/ErrorNames.h
@@ -0,0 +1,24 @@
+/* -*- 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 mozilla_ErrorNames_h
+#define mozilla_ErrorNames_h
+
+#include "nsError.h"
+
+class nsACString;
+
+namespace mozilla {
+
+// Maps the given nsresult to its symbolic name. For example,
+// GetErrorName(NS_OK, name) will result in name == "NS_OK".
+// When the symbolic name is unknown, name will be of the form
+// "NS_ERROR_GENERATE_SUCCESS(<module>, <code>)" or
+// "NS_ERROR_GENERATE_FAILURE(<module>, <code>)".
+void GetErrorName(nsresult rv, nsACString& name);
+
+}
+
+#endif // mozilla_ErrorNames_h
--- a/xpcom/base/moz.build
+++ b/xpcom/base/moz.build
@@ -71,16 +71,17 @@ if CONFIG['OS_ARCH'] == 'WINNT':
         SOURCES += ['pure_api.c']
 
 EXPORTS.mozilla += [
     'AvailableMemoryTracker.h',
     'ClearOnShutdown.h',
     'CountingAllocatorBase.h',
     'CycleCollectedJSRuntime.h',
     'Debug.h',
+    'ErrorNames.h',
     'LinuxUtils.h',
     'nsMemoryInfoDumper.h',
     'StackWalk.h',
     'StaticMutex.h',
     'StaticPtr.h',
     'SystemMemoryReporter.h',
     'VisualEventTracer.h',
 ]
@@ -92,16 +93,17 @@ SOURCES += [
 ]
 SOURCES['nsDebugImpl.cpp'].no_pgo = True
 
 UNIFIED_SOURCES += [
     'AvailableMemoryTracker.cpp',
     'ClearOnShutdown.cpp',
     'CycleCollectedJSRuntime.cpp',
     'Debug.cpp',
+    'ErrorNames.cpp',
     'nsConsoleMessage.cpp',
     'nsConsoleService.cpp',
     'nsCycleCollector.cpp',
     'nsDumpUtils.cpp',
     'nsErrorService.cpp',
     'nsGZFileWriter.cpp',
     'nsInterfaceRequestorAgg.cpp',
     'nsMemoryImpl.cpp',