Merge m-i to m-c
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 23 Feb 2014 08:46:03 -0800
changeset 170414 2621a1cc8c6c68a02ee63d209dd420de422fb6b1
parent 170413 2d5d5fd03050e166494177715470147cdb0906dc (current diff)
parent 170412 6d22d19bcd2fb95c871a8226dae2a5a4ae772e86 (diff)
child 170445 352a5a9b63e311d8163f6b4e845f61b4c37824d4
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge m-i to m-c
js/src/jit-test/tests/self-hosting/makewrappable.js
--- a/content/html/content/src/HTMLTrackElement.cpp
+++ b/content/html/content/src/HTMLTrackElement.cpp
@@ -56,16 +56,26 @@ NS_NewHTMLTrackElement(already_AddRefed<
   }
 
   return new mozilla::dom::HTMLTrackElement(aNodeInfo);
 }
 
 namespace mozilla {
 namespace dom {
 
+// Map html attribute string values to TextTrackKind enums.
+static MOZ_CONSTEXPR nsAttrValue::EnumTable kKindTable[] = {
+  { "subtitles", static_cast<int16_t>(TextTrackKind::Subtitles) },
+  { "captions", static_cast<int16_t>(TextTrackKind::Captions) },
+  { "descriptions", static_cast<int16_t>(TextTrackKind::Descriptions) },
+  { "chapters", static_cast<int16_t>(TextTrackKind::Chapters) },
+  { "metadata", static_cast<int16_t>(TextTrackKind::Metadata) },
+  { 0 }
+};
+
 // The default value for kKindTable is "subtitles"
 static MOZ_CONSTEXPR const char* kKindTableDefaultString = kKindTable->tag;
 
 /** HTMLTrackElement */
 HTMLTrackElement::HTMLTrackElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
 {
 #ifdef PR_LOGGING
--- a/content/html/content/src/HTMLTrackElement.h
+++ b/content/html/content/src/HTMLTrackElement.h
@@ -16,26 +16,16 @@
 #include "nsIDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIHttpChannel.h"
 
 namespace mozilla {
 namespace dom {
 
-// Map html attribute string values to TextTrackKind enums.
-static MOZ_CONSTEXPR nsAttrValue::EnumTable kKindTable[] = {
-  { "subtitles", static_cast<int16_t>(TextTrackKind::Subtitles) },
-  { "captions", static_cast<int16_t>(TextTrackKind::Captions) },
-  { "descriptions", static_cast<int16_t>(TextTrackKind::Descriptions) },
-  { "chapters", static_cast<int16_t>(TextTrackKind::Chapters) },
-  { "metadata", static_cast<int16_t>(TextTrackKind::Metadata) },
-  { 0 }
-};
-
 class WebVTTListener;
 
 class HTMLTrackElement MOZ_FINAL : public nsGenericHTMLElement
 {
 public:
   HTMLTrackElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~HTMLTrackElement();
 
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -4,16 +4,17 @@ support-files =
   iframe_messageChannel_pingpong.html
   iframe_messageChannel_post.html
   file_empty.html
   iframe_postMessage_solidus.html
 
 [test_Image_constructor.html]
 [test_appname_override.html]
 [test_bug913761.html]
+[test_clearTimeoutIntervalNoArg.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_document.all_unqualified.html]
 [test_domcursor.html]
 [test_domrequest.html]
 [test_e4x_for_each.html]
 [test_error.html]
 [test_gsp-qualified.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_clearTimeoutIntervalNoArg.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for clearTimeout/clearInterval with no arguments not throwing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+  clearTimeout();
+}, "clearTimeout with no args should not throw ");
+test(function() {
+  clearInterval();
+}, "clearInterval with no args should not throw ");
+</script>
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -17,12 +17,12 @@ ifneq (,$(MOZ_B2G_BT))
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 ifdef MOZ_B2G_BT_BLUEZ
 LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
 endif #MOZ_B2G_BT_BLUEZ
 else
 ifdef MOZ_ENABLE_DBUS
 LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
 CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
-CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
+CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
 endif #MOZ_ENABLE_DBUS
 endif #MOZ_WIDGET_TOOLKIT
 endif #MOZ_B2G_BT
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -61,16 +61,17 @@ if CONFIG['MOZ_B2G_BT']:
             'bluez/BluetoothHfpManager.cpp',
             'bluez/linux/BluetoothDBusService.cpp',
         ]
         LOCAL_INCLUDES += [
             'bluez',
             'bluez/linux',
         ]
         DEFINES['MOZ_BLUETOOTH_DBUS'] = True
+        DEFINES['HAVE_PTHREADS'] = True
 
     FINAL_LIBRARY = 'gklayout'
 
     LOCAL_INCLUDES += [
         'ipc',
     ]
 
 EXPORTS.mozilla.dom.bluetooth.ipc += [
--- a/dom/interfaces/base/nsIContentPrefService2.idl
+++ b/dom/interfaces/base/nsIContentPrefService2.idl
@@ -62,20 +62,33 @@ interface nsIContentPref;
  * The methods of callback objects are always called asynchronously.
  *
  * Observers are called after callbacks are called, but they are called in the
  * same turn of the event loop as callbacks.
  *
  * See nsIContentPrefCallback2 below for more information about callbacks.
  */
 
-[scriptable, uuid(86279644-6b86-4875-a228-2d2ff2f3e33b)]
+[scriptable, uuid(f2507add-dc39-48e0-9147-e0270376148b)]
 interface nsIContentPrefService2 : nsISupports
 {
   /**
+   * Gets all the preferences with the given name.
+   *
+   * @param name      The preferences' name.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleResult is called once for each preference unless
+   *                  no such preferences exist, in which case handleResult
+   *                  is not called at all.
+   */
+  void getByName(in AString name,
+                 in nsILoadContext context,
+                 in nsIContentPrefCallback2 callback);
+
+  /**
    * Gets the preference with the given domain and name.
    *
    * @param domain    The preference's domain.
    * @param name      The preference's name.
    * @param context   The private-browsing context, if any.
    * @param callback  handleResult is called once unless no such preference
    *                  exists, in which case handleResult is not called at all.
    */
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -311,16 +311,42 @@ TabChild::HandleEvent(nsIDOMEvent* aEven
     // This meta data may or may not have been a meta viewport tag. If it was,
     // we should handle it immediately.
     HandlePossibleViewportChange();
   }
 
   return NS_OK;
 }
 
+void
+TabChild::InitializeRootMetrics()
+{
+  // Calculate a really simple resolution that we probably won't
+  // be keeping, as well as putting the scroll offset back to
+  // the top-left of the page.
+  mLastRootMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
+  mLastRootMetrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
+  mLastRootMetrics.mZoom = mLastRootMetrics.CalculateIntrinsicScale();
+  mLastRootMetrics.mDevPixelsPerCSSPixel = mWidget->GetDefaultScale();
+  // We use ScreenToLayerScale(1) below in order to turn the
+  // async zoom amount into the gecko zoom amount.
+  mLastRootMetrics.mCumulativeResolution =
+    mLastRootMetrics.mZoom / mLastRootMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
+  // This is the root layer, so the cumulative resolution is the same
+  // as the resolution.
+  mLastRootMetrics.mResolution = mLastRootMetrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
+  mLastRootMetrics.mScrollOffset = CSSPoint(0, 0);
+}
+
+bool
+TabChild::HasValidInnerSize()
+{
+  return (mInnerSize.width != 0) && (mInnerSize.height != 0);
+}
+
 NS_IMETHODIMP
 TabChild::Observe(nsISupports *aSubject,
                   const char *aTopic,
                   const char16_t *aData)
 {
   if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
     nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
@@ -347,36 +373,26 @@ TabChild::Observe(nsISupports *aSubject,
 
         mContentDocumentIsDisplayed = true;
 
         // Reset CSS viewport and zoom to default on new page, then
         // calculate them properly using the actual metadata from the
         // page.
         SetCSSViewport(kDefaultViewportSize);
 
-        // Calculate a really simple resolution that we probably won't
-        // be keeping, as well as putting the scroll offset back to
-        // the top-left of the page.
-        mLastRootMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
-        mLastRootMetrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
-        mLastRootMetrics.mZoom = mLastRootMetrics.CalculateIntrinsicScale();
-        mLastRootMetrics.mDevPixelsPerCSSPixel = mWidget->GetDefaultScale();
-        // We use ScreenToLayerScale(1) below in order to turn the
-        // async zoom amount into the gecko zoom amount.
-        mLastRootMetrics.mCumulativeResolution =
-          mLastRootMetrics.mZoom / mLastRootMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
-        // This is the root layer, so the cumulative resolution is the same
-        // as the resolution.
-        mLastRootMetrics.mResolution = mLastRootMetrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
-        mLastRootMetrics.mScrollOffset = CSSPoint(0, 0);
-
-        utils->SetResolution(mLastRootMetrics.mResolution.scale,
-                             mLastRootMetrics.mResolution.scale);
-
-        HandlePossibleViewportChange();
+        // In some cases before-first-paint gets called before
+        // RecvUpdateDimensions is called and therefore before we have an
+        // mInnerSize value set. In such cases defer initializing the viewport
+        // until we we get an inner size.
+        if (HasValidInnerSize()) {
+          InitializeRootMetrics();
+          utils->SetResolution(mLastRootMetrics.mResolution.scale,
+                               mLastRootMetrics.mResolution.scale);
+          HandlePossibleViewportChange();
+        }
       }
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1453,26 +1469,37 @@ TabChild::RecvUpdateDimensions(const nsR
         return true;
     }
 
     mOuterRect.x = rect.x;
     mOuterRect.y = rect.y;
     mOuterRect.width = rect.width;
     mOuterRect.height = rect.height;
 
+    bool initialSizing = !HasValidInnerSize()
+                      && (size.width != 0 && size.height != 0);
+
     mOrientation = orientation;
     mInnerSize = ScreenIntSize::FromUnknownSize(
       gfx::IntSize(size.width, size.height));
     mWidget->Resize(0, 0, size.width, size.height,
                     true);
 
     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mWebNav);
     baseWin->SetPositionAndSize(0, 0, size.width, size.height,
                                 true);
 
+    if (initialSizing && mContentDocumentIsDisplayed) {
+      // If this is the first time we're getting a valid mInnerSize, and the
+      // before-first-paint event has already been handled, then we need to set
+      // up our default viewport here. See the corresponding call to
+      // InitializeRootMetrics in the before-first-paint handler.
+      InitializeRootMetrics();
+    }
+
     HandlePossibleViewportChange();
 
     return true;
 }
 
 void
 TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName,
                                         const nsACString& aJSONData)
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -406,16 +406,19 @@ private:
      * frame in the hierarchy which contains us.
      *
      * |aIsBrowserElement| indicates whether we're a browser (but not an app).
      */
     TabChild(ContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
 
     nsresult Init();
 
+    void InitializeRootMetrics();
+    bool HasValidInnerSize();
+
     // Notify others that our TabContext has been updated.  (At the moment, this
     // sets the appropriate app-id and is-browser flags on our docshell.)
     //
     // You should call this after calling TabContext::SetTabContext().  We also
     // call this during Init().
     void NotifyTabContextUpdated();
 
     bool UseDirectCompositor();
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1,10 +1,8 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaManager.h"
 
 #include "MediaStreamGraph.h"
 #include "GetUserMediaRequest.h"
@@ -237,20 +235,18 @@ public:
     , mWindowID(aWindowID)
     , mManager(MediaManager::GetInstance()) {}
 
   NS_IMETHOD
   Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
-    nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> success;
-    nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error;
-    success.swap(mSuccess);
-    error.swap(mError);
+    nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> success(mSuccess);
+    nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
     // Only run if window is still on our active list.
     if (!mManager->IsWindowStillActive(mWindowID)) {
       return NS_OK;
     }
 
     nsCOMPtr<nsIWritableVariant> devices =
       do_CreateInstance("@mozilla.org/variant;1");
@@ -277,18 +273,18 @@ public:
                           static_cast<const void*>(tmp.Elements())
                         ));
 
     success->OnSuccess(devices);
     return NS_OK;
   }
 
 private:
-  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
+  already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   nsAutoPtr<nsTArray<nsCOMPtr<nsIMediaDevice> > > mDevices;
   uint64_t mWindowID;
   nsRefPtr<MediaManager> mManager;
 };
 
 // Handle removing GetUserMediaCallbackMediaStreamListener from main thread
 class GetUserMediaListenerRemove: public nsRunnable
 {
@@ -1086,26 +1082,25 @@ public:
                                           mLoopbackVideoDevice));
     {
       ScopedDeletePtr<SourceSet> s (GetSources(backend, mConstraints.mAudiom,
                                         &MediaEngine::EnumerateAudioDevices,
                                         mLoopbackAudioDevice));
       final->MoveElementsFrom(*s);
     }
     NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mWindowId,
-                                                              mSuccess.forget(),
-                                                              mError.forget(),
+                                                              mSuccess, mError,
                                                               final.forget()));
     return NS_OK;
   }
 
 private:
   MediaStreamConstraintsInternal mConstraints;
-  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
+  already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   nsRefPtr<MediaManager> mManager;
   uint64_t mWindowId;
   const nsString mCallId;
   // Audio & Video loopback devices to be used based on
   // the preference settings. This is currently used for
   // automated media tests only.
   char* mLoopbackAudioDevice;
   char* mLoopbackVideoDevice;
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -83,20 +83,20 @@ typedef any Transferable;
 Window implements GlobalEventHandlers;
 Window implements WindowEventHandlers;
 
 // http://www.whatwg.org/specs/web-apps/current-work/
 [NoInterfaceObject]
 interface WindowTimers {
   [Throws] long setTimeout(Function handler, optional long timeout = 0, any... arguments);
   [Throws] long setTimeout(DOMString handler, optional long timeout = 0, any... unused);
-  [Throws] void clearTimeout(long handle);
+  [Throws] void clearTimeout(optional long handle = 0);
   [Throws] long setInterval(Function handler, optional long timeout, any... arguments);
   [Throws] long setInterval(DOMString handler, optional long timeout, any... unused);
-  [Throws] void clearInterval(long handle);
+  [Throws] void clearInterval(optional long handle = 0);
 };
 Window implements WindowTimers;
 
 // http://www.whatwg.org/specs/web-apps/current-work/
 [NoInterfaceObject]
 interface WindowBase64 {
   [Throws] DOMString btoa(DOMString btoa);
   [Throws] DOMString atob(DOMString atob);
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -949,17 +949,17 @@ nsXBLBinding::DoInitJSClass(JSContext *c
       return NS_ERROR_FAILURE;
     }
     if (parent_proto) {
       // We need to create a unique classname based on aClassName and
       // id.  Append a space (an invalid URI character) to ensure that
       // we don't have accidental collisions with the case when parent_proto is
       // null and aClassName ends in some bizarre numbers (yeah, it's unlikely).
       JS::Rooted<jsid> parent_proto_id(cx);
-      if (!::JS_GetObjectId(cx, parent_proto, parent_proto_id.address())) {
+      if (!::JS_GetObjectId(cx, parent_proto, &parent_proto_id)) {
         // Probably OOM
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       // One space, maybe "0x", at most 16 chars (on a 64-bit system) of long,
       // and a null-terminator (which PR_snprintf ensures is there even if the
       // string representation of what we're printing does not fit in the buffer
       // provided).
--- a/gfx/2d/GenericRefCounted.h
+++ b/gfx/2d/GenericRefCounted.h
@@ -48,21 +48,22 @@ class GenericRefCounted : public Generic
     GenericRefCounted() : refCnt(0) { }
 
     virtual ~GenericRefCounted() {
       MOZ_ASSERT(refCnt == detail::DEAD);
     }
 
   public:
     virtual void AddRef() {
+      MOZ_ASSERT(int32_t(refCnt) >= 0);
       ++refCnt;
     }
 
     virtual void Release() {
-      MOZ_ASSERT(refCnt > 0);
+      MOZ_ASSERT(int32_t(refCnt) > 0);
       if (0 == --refCnt) {
 #ifdef DEBUG
         refCnt = detail::DEAD;
 #endif
         delete this;
       }
     }
 
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -10,34 +10,33 @@
 #include <ctype.h>
 
 #include "GLContext.h"
 #include "GLBlitHelper.h"
 #include "GLBlitTextureImageHelper.h"
 #include "GLReadTexImageHelper.h"
 
 #include "gfxCrashReporterUtils.h"
-#include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "GLContextProvider.h"
 #include "GLTextureImage.h"
 #include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
 #include "prenv.h"
 #include "prlink.h"
 #include "ScopedGLHelpers.h"
 #include "SurfaceStream.h"
 #include "GfxTexturesReporter.h"
 #include "TextureGarbageBin.h"
 #include "gfx2DGlue.h"
+#include "gfxPrefs.h"
 
 #include "OGLShaderProgram.h" // for ShaderProgramType
 
 #include "mozilla/DebugOnly.h"
-#include "mozilla/Preferences.h"
 
 #ifdef XP_MACOSX
 #include <CoreServices/CoreServices.h>
 #include "gfxColor.h"
 #endif
 
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
@@ -303,17 +302,17 @@ GLContext::InitWithPrefix(const char *pr
 {
     ScopedGfxFeatureReporter reporter("GL Context");
 
     if (mInitialized) {
         reporter.SetSuccessful();
         return true;
     }
 
-    mWorkAroundDriverBugs = gfxPlatform::GetPlatform()->WorkAroundDriverBugs();
+    mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs();
 
     SymLoadStruct symbols[] = {
         { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", nullptr } },
         { (PRFuncPtr*) &mSymbols.fBlendColor, { "BlendColor", nullptr } },
@@ -1328,17 +1327,17 @@ GLContext::ChooseGLFormats(const Surface
             formats.color_rbFormat  = LOCAL_GL_RGBA8;
         } else {
             formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
             formats.color_texFormat = LOCAL_GL_RGB;
             formats.color_rbFormat  = LOCAL_GL_RGB8;
         }
     }
 
-    uint32_t msaaLevel = Preferences::GetUint("gl.msaa-level", 2);
+    uint32_t msaaLevel = gfxPrefs::MSAALevel();
     GLsizei samples = msaaLevel * msaaLevel;
     samples = std::min(samples, mMaxSamples);
 
     // Bug 778765.
     if (WorkAroundDriverBugs() && samples == 1) {
         samples = 0;
     }
     formats.samples = samples;
--- a/gfx/qcms/Makefile.in
+++ b/gfx/qcms/Makefile.in
@@ -36,18 +36,16 @@ ifdef GNU_CC
 	CSRCS += transform-altivec.c
 	ALTIVEC_FLAGS=-maltivec
 endif
 endif
 endif
 
 include $(topsrcdir)/config/rules.mk
 
-CFLAGS          += -DMOZ_QCMS
-
 # Disable spammy "missing initializer" GCC warning
 ifdef GNU_CC
 CFLAGS += -Wno-missing-field-initializers
 endif # GNU_CC
 
 # special rules for transform-sse*.c to get the right cflags. (taken from pixman/src/Makefile.in)
 transform-sse1.$(OBJ_SUFFIX): COMPILE_CFLAGS += $(SSE1_FLAGS)
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -450,18 +450,16 @@ gfxPlatform::Init()
     Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
 
     gPlatform->mFontPrefsObserver = new FontPrefsObserver();
     Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
 
     gPlatform->mOrientationSyncPrefsObserver = new OrientationSyncPrefsObserver();
     Preferences::AddStrongObserver(gPlatform->mOrientationSyncPrefsObserver, "layers.orientation.sync.timeout");
 
-    gPlatform->mWorkAroundDriverBugs = Preferences::GetBool("gfx.work-around-driver-bugs", true);
-
     mozilla::Preferences::AddBoolVarCache(&gPlatform->mWidgetUpdateFlashing,
                                           "nglayout.debug.widget_update_flashing");
 
     mozilla::gl::GLContext::PlatformStartup();
 
 #ifdef MOZ_WIDGET_ANDROID
     // Texture pool init
     mozilla::gl::TexturePoolOGL::Init();
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -598,18 +598,16 @@ public:
     virtual gfxImageFormat GetOffscreenFormat()
     { return gfxImageFormat::RGB24; }
 
     /**
      * Returns a logger if one is available and logging is enabled
      */
     static PRLogModuleInfo* GetLog(eGfxLog aWhichLog);
 
-    bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
-
     virtual int GetScreenDepth() const;
 
     bool WidgetUpdateFlashing() const { return mWidgetUpdateFlashing; }
 
     uint32_t GetOrientationSyncMillis() const;
 
     /**
      * Return the layer debugging options to use browser-wide.
@@ -737,17 +735,16 @@ private:
     // The fallback draw target backend to use for canvas, if the preferred backend fails
     mozilla::gfx::BackendType mFallbackCanvasBackend;
     // The backend to use for content
     mozilla::gfx::BackendType mContentBackend;
     // Bitmask of backend types we can use to render content
     uint32_t mContentBackendBitmask;
 
     mozilla::widget::GfxInfoCollector<gfxPlatform> mAzureCanvasBackendCollector;
-    bool mWorkAroundDriverBugs;
 
     mozilla::RefPtr<mozilla::gfx::DrawEventRecorder> mRecorder;
     bool mWidgetUpdateFlashing;
     uint32_t mOrientationSyncMillis;
     bool mLayersPreferMemoryOverShmem;
     bool mLayersUseDeprecated;
     bool mDrawLayerBorders;
     bool mDrawTileBorders;
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -13,50 +13,50 @@
 // First time gfxPrefs::One() needs to be called on the main thread,
 // before any of the methods accessing the values are used, but after
 // the Preferences system has been initialized.
 
 // The static methods to access the preference value are safe to call
 // from any thread after that first call.
 
 // To register a preference, you need to add a line in this file using
-// the DECL_GFX_PREFS macro.
+// the DECL_GFX_PREF macro.
 //
 // Update argument controls whether we read the preference value and save it
 // or connect with a callback.  See UpdatePolicy enum below.
 // Pref is the string with the preference name.
 // Name argument is the name of the static function to create.
 // Type is the type of the preference - bool, int32_t, uint32_t.
 // Default is the default value for the preference.
 //
 // For example this line in the .h:
-//   DECL_GFX_PREFS(Once,"layers.dump",LayersDump,bool,false);
+//   DECL_GFX_PREF(Once,"layers.dump",LayersDump,bool,false);
 // means that you can call
 //   bool var = gfxPrefs::LayersDump();
 // from any thread, but that you will only get the preference value of
 // "layers.dump" as it was set at the start of the session. If the value
 // was not set, the default would be false.
 //
 // In another example, this line in the .h:
-//   DECL_GFX_PREFS(Live,"gl.msaa-level",MSAALevel,uint32_t,2);
+//   DECL_GFX_PREF(Live,"gl.msaa-level",MSAALevel,uint32_t,2);
 // means that every time you call
 //   uint32_t var = gfxPrefs::MSAALevel();
 // from any thread, you will get the most up to date preference value of
 // "gl.msaa-level".  If the value is not set, the default would be 2.
 
 // Note that changing a preference from Live to Once is now as simple
 // as changing the Update argument.  If your code worked before, it will
 // keep working, and behave as if the user never changes the preference.
 // Things are a bit more complicated and perhaps even dangerous when
 // going from Once to Live, or indeed setting a preference to be Live
 // in the first place, so be careful.  You need to be ready for the
 // values changing mid execution, and if you're using those preferences
 // in any setup and initialization, you may need to do extra work.
 
-#define DECL_GFX_PREFS(Update, Pref, Name, Type, Default)                     \
+#define DECL_GFX_PREF(Update, Pref, Name, Type, Default)                     \
 public:                                                                       \
 static Type Name() { MOZ_ASSERT(Exists()); return One().mPref##Name.mValue; } \
 private:                                                                      \
 static const char* Get##Name##PrefName() { return Pref; }                     \
 PrefTemplate<UpdatePolicy::Update, Type, Default, Get##Name##PrefName> mPref##Name
 
 class gfxPrefs;
 class gfxPrefs MOZ_FINAL
@@ -94,24 +94,28 @@ private:
           MOZ_CRASH();
           break;
       }
     }
     T mValue;
   };
 
 public:
-  // This is where DECL_GFX_PREFS for each of the preferences should go.
+  // This is where DECL_GFX_PREF for each of the preferences should go.
   // We will keep these in an alphabetical order to make it easier to see if
   // a method accessing a pref already exists. Just add yours in the list.
 
+  DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
+
+  DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
+
 public:
   // Manage the singleton:
   static gfxPrefs& One()
-  { 
+  {
     if (!sInstance) {
       sInstance = new gfxPrefs;
     }
     return *sInstance;
   }
   static void Destroy();
   static bool Exists();
 
@@ -128,11 +132,11 @@ private:
   static uint32_t PrefGet(const char*, uint32_t);
 
   gfxPrefs();
   ~gfxPrefs();
   gfxPrefs(const gfxPrefs&) MOZ_DELETE;
   gfxPrefs& operator=(const gfxPrefs&) MOZ_DELETE;
 };
 
-#undef DECL_GFX_PREFS /* Don't need it outside of this file */
+#undef DECL_GFX_PREF /* Don't need it outside of this file */
 
 #endif /* GFX_PREFS_H */
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -319,16 +319,32 @@ extern JS_FRIEND_API(void)
 DisableGenerationalGC(JSRuntime *rt);
 
 /*
  * Generational GC may be re-enabled at runtime.
  */
 extern JS_FRIEND_API(void)
 EnableGenerationalGC(JSRuntime *rt);
 
+/* Ensure that generational GC is disabled within some scope. */
+class JS_FRIEND_API(AutoDisableGenerationalGC)
+{
+    JSRuntime *runtime;
+
+  public:
+    AutoDisableGenerationalGC(JSRuntime *rt)
+      : runtime(rt)
+    {
+        DisableGenerationalGC(rt);
+    }
+    ~AutoDisableGenerationalGC() {
+        EnableGenerationalGC(runtime);
+    }
+};
+
 /*
  * Returns true if generational allocation and collection is currently enabled
  * on the given runtime.
  */
 extern JS_FRIEND_API(bool)
 IsGenerationalGCEnabled(JSRuntime *rt);
 
 /*
--- a/js/public/Id.h
+++ b/js/public/Id.h
@@ -16,19 +16,20 @@
 // such as in JS_NextProperty. Embeddings must not pass JSID_VOID into JSAPI
 // entry points expecting a jsid and do not need to handle JSID_VOID in hooks
 // receiving a jsid except when explicitly noted in the API contract.
 //
 // A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or
 // JS_IdToValue must be used instead.
 
 #include "mozilla/NullPtr.h"
- 
+
 #include "jstypes.h"
 
+#include "js/HeapAPI.h"
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 
 struct jsid
 {
     size_t asBits;
     bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
@@ -111,16 +112,17 @@ JSID_TO_OBJECT(jsid id)
 }
 
 static MOZ_ALWAYS_INLINE jsid
 OBJECT_TO_JSID(JSObject *obj)
 {
     jsid id;
     MOZ_ASSERT(obj != nullptr);
     MOZ_ASSERT(((size_t)obj & JSID_TYPE_MASK) == 0);
+    JS_ASSERT(!js::gc::IsInsideNursery(js::gc::GetGCThingRuntime(obj), obj));
     JSID_BITS(id) = ((size_t)obj | JSID_TYPE_OBJECT);
     return id;
 }
 
 static MOZ_ALWAYS_INLINE bool
 JSID_IS_GCTHING(jsid id)
 {
     return JSID_IS_STRING(id) || JSID_IS_OBJECT(id);
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -163,49 +163,16 @@ function IsObject(v) {
     return (typeof v === "object" && v !== null) ||
            typeof v === "function" ||
            (typeof v === "undefined" && v !== undefined);
 }
 
 
 /********** Testing code **********/
 
-// This code enables testing of the custom allow-nothing wrappers used for
-// objects and functions crossing the self-hosting compartment boundaries.
-// Functions marked as wrappable won't be cloned into content compartments;
-// they're called inside the self-hosting compartment itself. Calling is the
-// only valid operation on them. In turn, the only valid way they can use their
-// object arguments is as keys in maps. Doing anything else with them throws.
-var wrappersTestMap = new WeakMap();
-function testWrappersAllowUseAsKey(o) {
-  wrappersTestMap.set(o, o);
-  var mappedO = wrappersTestMap.get(o);
-  wrappersTestMap.clear();
-  return mappedO;
-}
-function testWrappersForbidAccess(o, operation) {
-  try {
-    switch (operation) {
-      case 'get': var result = o.prop; break;
-      case 'set': o.prop2 = 'value'; break;
-      case 'call': o(); break;
-      case '__proto__':
-        Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set.call(o, new Object());
-        break;
-    }
-  } catch (e) {
-    // Got the expected exception.
-    return /denied/.test(e);
-  }
-  return false;
-}
-
-MakeWrappable(testWrappersAllowUseAsKey);
-MakeWrappable(testWrappersForbidAccess);
-
 #ifdef ENABLE_PARALLEL_JS
 
 /**
  * Internal debugging tool: checks that the given `mode` permits
  * sequential execution
  */
 function AssertSequentialIsOK(mode) {
   if (mode && mode.mode && mode.mode !== "seq" && ParallelTestsShouldPass())
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -159,35 +159,38 @@ frontend::MaybeCallSourceHandler(JSConte
 
     if (listener) {
         void *listenerTSData;
         listener(options.filename(), options.lineno, chars, length,
                  &listenerTSData, listenerData);
     }
 }
 
-static bool
-SetScriptSourceFilename(ExclusiveContext *cx, ScriptSource *ss,
-                        const ReadOnlyCompileOptions &options)
+ScriptSourceObject *
+frontend::CreateScriptSourceObject(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
 {
+    ScriptSource *ss = cx->new_<ScriptSource>(options.originPrincipals());
+    if (!ss)
+        return nullptr;
+
     if (options.hasIntroductionInfo) {
         const char *filename = options.filename() ? options.filename() : "<unknown>";
         JS_ASSERT(options.introductionType != nullptr);
 
         if (!ss->setIntroducedFilename(cx, filename, options.introductionLineno,
                                        options.introductionType, options.introducerFilename()))
-            return false;
+            return nullptr;
 
         ss->setIntroductionOffset(options.introductionOffset);
     } else {
         if (options.filename() && !ss->setFilename(cx, options.filename()))
-            return false;
+            return nullptr;
     }
 
-    return true;
+    return ScriptSourceObject::create(cx, ss, options);
 }
 
 JSScript *
 frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject scopeChain,
                         HandleScript evalCaller,
                         const ReadOnlyCompileOptions &options,
                         const jschar *chars, size_t length,
                         JSString *source_ /* = nullptr */,
@@ -213,26 +216,22 @@ frontend::CompileScript(ExclusiveContext
      */
     JS_ASSERT_IF(evalCaller, options.compileAndGo);
     JS_ASSERT_IF(evalCaller, options.forEval);
     JS_ASSERT_IF(staticLevel != 0, evalCaller);
 
     if (!CheckLength(cx, length))
         return nullptr;
     JS_ASSERT_IF(staticLevel != 0, options.sourcePolicy != CompileOptions::LAZY_SOURCE);
-    ScriptSource *ss = cx->new_<ScriptSource>(options.originPrincipals());
-    if (!ss)
+
+    RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
+    if (!sourceObject)
         return nullptr;
 
-    if (!SetScriptSourceFilename(cx, ss, options))
-        return nullptr;
-
-    RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss, options));
-    if (!sourceObject)
-        return nullptr;
+    ScriptSource *ss = sourceObject->source();
 
     SourceCompressionTask mysct(cx);
     SourceCompressionTask *sct = extraSct ? extraSct : &mysct;
 
     switch (options.sourcePolicy) {
       case CompileOptions::SAVE_SOURCE:
         if (!ss->setSourceCopy(cx, chars, length, false, sct))
             return nullptr;
@@ -509,24 +508,22 @@ CompileFunctionBody(JSContext *cx, Mutab
     // FIXME: make Function pass in two strings and parse them as arguments and
     // ProgramElements respectively.
     SkipRoot skip(cx, &chars);
 
     MaybeCallSourceHandler(cx, options, chars, length);
 
     if (!CheckLength(cx, length))
         return false;
-    ScriptSource *ss = cx->new_<ScriptSource>(options.originPrincipals());
-    if (!ss)
-        return false;
-    if (!SetScriptSourceFilename(cx, ss, options))
-        return false;
-    RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss, options));
+
+    RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
     if (!sourceObject)
-        return false;
+        return nullptr;
+    ScriptSource *ss = sourceObject->source();
+
     SourceCompressionTask sct(cx);
     JS_ASSERT(options.sourcePolicy != CompileOptions::LAZY_SOURCE);
     if (options.sourcePolicy == CompileOptions::SAVE_SOURCE) {
         if (!ss->setSourceCopy(cx, chars, length, true, &sct))
             return false;
     }
 
     bool canLazilyParse = CanLazilyParse(cx, options);
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -34,16 +34,19 @@ bool
 CompileFunctionBody(JSContext *cx, MutableHandleFunction fun,
                     const ReadOnlyCompileOptions &options,
                     const AutoNameVector &formals, const jschar *chars, size_t length);
 bool
 CompileStarGeneratorBody(JSContext *cx, MutableHandleFunction fun,
                          const ReadOnlyCompileOptions &options,
                          const AutoNameVector &formals, const jschar *chars, size_t length);
 
+ScriptSourceObject *
+CreateScriptSourceObject(ExclusiveContext *cx, const ReadOnlyCompileOptions &options);
+
 /*
  * This should be called while still on the main thread if compilation will
  * occur on a worker thread.
  */
 void
 MaybeCallSourceHandler(JSContext *cx, const ReadOnlyCompileOptions &options,
                        const jschar *chars, size_t length);
 
--- a/js/src/jit-test/tests/TypedObject/neutertypedobj.js
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobj.js
@@ -1,8 +1,11 @@
+// FIXME bug 975456
+quit();
+
 if (!this.hasOwnProperty("TypedObject"))
   quit();
 
 var {StructType, uint32, storage} = TypedObject;
 var S = new StructType({f: uint32, g: uint32});
 
 function readFromS(s) {
   return s.f + s.g;
--- a/js/src/jit-test/tests/TypedObject/neutertypedobjsizedarray.js
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobjsizedarray.js
@@ -1,8 +1,11 @@
+// FIXME bug 975456
+quit();
+
 // Test the case where we neuter an instance of a fixed-sized array.
 // This is a bit of a tricky case because we cannot (necessarily) fold
 // the neuter check into the bounds check, as we obtain the bounds
 // directly from the type.
 
 if (!this.hasOwnProperty("TypedObject"))
   quit();
 
--- a/js/src/jit-test/tests/parallel/spew.js
+++ b/js/src/jit-test/tests/parallel/spew.js
@@ -1,9 +1,11 @@
 load(libdir + "parallelarray-helpers.js");
 
-var spew = getSelfHostedValue("ParallelSpew");
+try {
+    var spew = getSelfHostedValue("ParallelSpew");
+} catch (e) {}
 if (getBuildConfiguration().parallelJS && spew) {
   assertParallelExecSucceeds(
     function (m) { Array.buildPar(minItemsTestingThreshold,
                                   function (i) { spew(i + ""); }); },
     function (r) { return true; });
 }
deleted file mode 100644
--- a/js/src/jit-test/tests/self-hosting/makewrappable.js
+++ /dev/null
@@ -1,36 +0,0 @@
-
-var testObject = {prop:'value'};
-
-var testWrappersAllowUseAsKey = getSelfHostedValue('testWrappersAllowUseAsKey');
-assertEq(typeof testWrappersAllowUseAsKey, 'function');
-assertEq(testWrappersAllowUseAsKey(testObject), testObject);
-
-var testWrappersForbidAccess = getSelfHostedValue('testWrappersForbidAccess');
-assertEq(typeof testWrappersForbidAccess, 'function');
-assertEq(testWrappersForbidAccess(testObject, 'get'), true);
-assertEq(testWrappersForbidAccess(testObject, 'set'), true);
-assertEq(testWrappersForbidAccess(function(){}, 'call'), true);
-assertEq(testWrappersForbidAccess(testObject, '__proto__'), true);
-
-var wrappedFunction = testWrappersForbidAccess;
-function testWrappersAllowCallsOnly(fun, operation) {
-  try {
-    switch (operation) {
-      case 'get': var result = fun.prop; break;
-      case 'set': fun.prop2 = 'value'; break;
-      case 'call': o(); break;
-      case '__proto__':
-        Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set.call(fun, new Object());
-        break;
-    }
-  } catch (e) {
-    // Got the expected exception.
-    return /denied/.test(e);
-  }
-  return false;
-}
-
-assertEq(testWrappersAllowCallsOnly(wrappedFunction, 'get'), true);
-assertEq(testWrappersAllowCallsOnly(wrappedFunction, 'set'), true);
-assertEq(testWrappersAllowCallsOnly(wrappedFunction, '__proto__'), true);
-assertEq(testWrappersAllowCallsOnly(wrappedFunction, 'call'), false);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -692,27 +692,33 @@ ICStubCompiler::guardProfilingEnabled(Ma
 
     // Check if profiling is enabled
     uint32_t *enabledAddr = cx->runtime()->spsProfiler.addressOfEnabled();
     masm.branch32(Assembler::Equal, AbsoluteAddress(enabledAddr), Imm32(0), skip);
 }
 
 #ifdef JSGC_GENERATIONAL
 inline bool
-ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, Register scratch,
-                                         GeneralRegisterSet saveRegs)
+ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
+                                         Register scratch, GeneralRegisterSet saveRegs)
 {
     Nursery &nursery = cx->runtime()->gcNursery;
 
     Label skipBarrier;
+    masm.branchTestObject(Assembler::NotEqual, val, &skipBarrier);
+
     Label isTenured;
     masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.start()), &isTenured);
     masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.heapEnd()), &skipBarrier);
     masm.bind(&isTenured);
 
+    Register valReg = masm.extractObject(val, scratch);
+    masm.branchPtr(Assembler::Below, valReg, ImmWord(nursery.start()), &skipBarrier);
+    masm.branchPtr(Assembler::AboveOrEqual, valReg, ImmWord(nursery.heapEnd()), &skipBarrier);
+
     // void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
 #ifdef JS_CODEGEN_ARM
     saveRegs.add(BaselineTailCallReg);
 #endif
     saveRegs = GeneralRegisterSet::Intersect(saveRegs, GeneralRegisterSet::Volatile());
     masm.PushRegsInMask(saveRegs);
     masm.setupUnalignedABICall(2, scratch);
     masm.movePtr(ImmPtr(cx->runtime()), scratch);
@@ -5210,27 +5216,23 @@ ICSetElem_Dense::Compiler::generateStubC
 
     // Don't overwrite R0 becuase |obj| might overlap with it, and it's needed
     // for post-write barrier later.
     ValueOperand tmpVal = regs.takeAnyValue();
     masm.loadValue(valueAddr, tmpVal);
     EmitPreBarrier(masm, element, MIRType_Value);
     masm.storeValue(tmpVal, element);
     regs.add(key);
-    regs.add(tmpVal);
 #ifdef JSGC_GENERATIONAL
-    Label skipBarrier;
-    masm.branchTestObject(Assembler::NotEqual, tmpVal, &skipBarrier);
     {
         Register r = regs.takeAny();
         GeneralRegisterSet saveRegs;
-        emitPostWriteBarrierSlot(masm, obj, r, saveRegs);
+        emitPostWriteBarrierSlot(masm, obj, tmpVal, r, saveRegs);
         regs.add(r);
     }
-    masm.bind(&skipBarrier);
 #endif
     EmitReturnFromIC(masm);
 
 
     // Failure case - fail but first unstow R0 and R1
     masm.bind(&failureUnstow);
     EmitUnstowICValues(masm, 2);
 
@@ -5397,27 +5399,23 @@ ICSetElemDenseAddCompiler::generateStubC
     masm.bind(&dontConvertDoubles);
 
     // Write the value.  No need for pre-barrier since we're not overwriting an old value.
     ValueOperand tmpVal = regs.takeAnyValue();
     BaseIndex element(scratchReg, key, TimesEight);
     masm.loadValue(valueAddr, tmpVal);
     masm.storeValue(tmpVal, element);
     regs.add(key);
-    regs.add(tmpVal);
 #ifdef JSGC_GENERATIONAL
-    Label skipBarrier;
-    masm.branchTestObject(Assembler::NotEqual, tmpVal, &skipBarrier);
     {
         Register r = regs.takeAny();
         GeneralRegisterSet saveRegs;
-        emitPostWriteBarrierSlot(masm, obj, r, saveRegs);
+        emitPostWriteBarrierSlot(masm, obj, tmpVal, r, saveRegs);
         regs.add(r);
     }
-    masm.bind(&skipBarrier);
 #endif
     EmitReturnFromIC(masm);
 
     // Failure case - fail but first unstow R0 and R1
     masm.bind(&failureUnstow);
     EmitUnstowICValues(masm, 2);
 
     // Failure case - jump to next stub
@@ -7392,26 +7390,23 @@ ICSetProp_Native::Compiler::generateStub
 
     // Perform the store.
     masm.load32(Address(BaselineStubReg, ICSetProp_Native::offsetOfOffset()), scratch);
     EmitPreBarrier(masm, BaseIndex(holderReg, scratch, TimesOne), MIRType_Value);
     masm.storeValue(R1, BaseIndex(holderReg, scratch, TimesOne));
     if (holderReg != objReg)
         regs.add(holderReg);
 #ifdef JSGC_GENERATIONAL
-    Label skipBarrier;
-    masm.branchTestObject(Assembler::NotEqual, R1, &skipBarrier);
     {
         Register scr = regs.takeAny();
         GeneralRegisterSet saveRegs;
         saveRegs.add(R1);
-        emitPostWriteBarrierSlot(masm, objReg, scr, saveRegs);
+        emitPostWriteBarrierSlot(masm, objReg, R1, scr, saveRegs);
         regs.add(scr);
     }
-    masm.bind(&skipBarrier);
 #endif
 
     // The RHS has to be in R0.
     masm.moveValue(R1, R0);
     EmitReturnFromIC(masm);
 
     // Failure case - jump to next stub
     masm.bind(&failure);
@@ -7517,25 +7512,22 @@ ICSetPropNativeAddCompiler::generateStub
     // initialization.
     masm.load32(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfOffset()), scratch);
     masm.storeValue(R1, BaseIndex(holderReg, scratch, TimesOne));
 
     if (holderReg != objReg)
         regs.add(holderReg);
 
 #ifdef JSGC_GENERATIONAL
-    Label skipBarrier;
-    masm.branchTestObject(Assembler::NotEqual, R1, &skipBarrier);
     {
         Register scr = regs.takeAny();
         GeneralRegisterSet saveRegs;
         saveRegs.add(R1);
-        emitPostWriteBarrierSlot(masm, objReg, scr, saveRegs);
-    }
-    masm.bind(&skipBarrier);
+        emitPostWriteBarrierSlot(masm, objReg, R1, scr, saveRegs);
+    }
 #endif
 
     // The RHS has to be in R0.
     masm.moveValue(R1, R0);
     EmitReturnFromIC(masm);
 
     // Failure case - jump to next stub
     masm.bind(&failureUnstow);
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -1072,18 +1072,18 @@ class ICStubCompiler
           default:
             MOZ_ASSUME_UNREACHABLE("Invalid numInputs");
         }
 
         return regs;
     }
 
 #ifdef JSGC_GENERATIONAL
-    inline bool emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, Register scratch,
-                                         GeneralRegisterSet saveRegs);
+    inline bool emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
+                                         Register scratch, GeneralRegisterSet saveRegs);
 #endif
 
   public:
     virtual ICStub *getStub(ICStubSpace *space) = 0;
 
     ICStubSpace *getStubSpace(JSScript *script) {
         if (ICStub::CanMakeCalls(kind))
             return script->baselineScript()->fallbackStubSpace();
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1347,23 +1347,16 @@ JS_GetClassObject(JSContext *cx, JSProto
 JS_PUBLIC_API(bool)
 JS_GetClassPrototype(JSContext *cx, JSProtoKey key, MutableHandleObject objp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_GetClassPrototype(cx, key, objp);
 }
 
-JS_PUBLIC_API(JSProtoKey)
-JS_IdentifyClassPrototype(JSObject *obj)
-{
-    JS_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
-    return js_IdentifyClassPrototype(obj);
-}
-
 extern JS_PUBLIC_API(JSProtoKey)
 JS_IdToProtoKey(JSContext *cx, HandleId id)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     if (!JSID_IS_ATOM(id))
         return JSProto_Null;
@@ -2414,21 +2407,30 @@ JS_GetConstructor(JSContext *cx, HandleO
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
                              proto->getClass()->name);
         return nullptr;
     }
     return &cval.toObject();
 }
 
 JS_PUBLIC_API(bool)
-JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
+JS_GetObjectId(JSContext *cx, HandleObject obj, MutableHandleId idp)
 {
     AssertHeapIsIdle(cx);
     assertSameCompartment(cx, obj);
-    *idp = OBJECT_TO_JSID(obj);
+
+#ifdef JSGC_GENERATIONAL
+    // Ensure that the object is tenured before returning it.
+    if (IsInsideNursery(cx->runtime(), obj)) {
+        MinorGC(cx, JS::gcreason::EVICT_NURSERY);
+        MOZ_ASSERT(!IsInsideNursery(cx->runtime(), obj));
+    }
+#endif
+
+    idp.set(OBJECT_TO_JSID(obj));
     return true;
 }
 
 namespace {
 
 class AutoHoldZone
 {
   public:
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1765,18 +1765,33 @@ extern JS_PUBLIC_API(bool)
 JS_EnumerateStandardClasses(JSContext *cx, JS::HandleObject obj);
 
 extern JS_PUBLIC_API(bool)
 JS_GetClassObject(JSContext *cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);
 
 extern JS_PUBLIC_API(bool)
 JS_GetClassPrototype(JSContext *cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);
 
+namespace JS {
+
+/*
+ * Determine if the given object is an instance or prototype for a standard
+ * class. If so, return the associated JSProtoKey. If not, return JSProto_Null.
+ */
+
 extern JS_PUBLIC_API(JSProtoKey)
-JS_IdentifyClassPrototype(JSObject *obj);
+IdentifyStandardInstance(JSObject *obj);
+
+extern JS_PUBLIC_API(JSProtoKey)
+IdentifyStandardPrototype(JSObject *obj);
+
+extern JS_PUBLIC_API(JSProtoKey)
+IdentifyStandardInstanceOrPrototype(JSObject *obj);
+
+} /* namespace JS */
 
 extern JS_PUBLIC_API(JSProtoKey)
 JS_IdToProtoKey(JSContext *cx, JS::HandleId id);
 
 /*
  * Returns the original value of |Function.prototype| from the global object in
  * which |forObj| was created.
  */
@@ -2550,17 +2565,17 @@ extern JS_PUBLIC_API(JSObject *)
 JS_GetConstructor(JSContext *cx, JS::Handle<JSObject*> proto);
 
 /*
  * Get a unique identifier for obj, good for the lifetime of obj (even if it
  * is moved by a copying GC).  Return false on failure (likely out of memory),
  * and true with *idp containing the unique id on success.
  */
 extern JS_PUBLIC_API(bool)
-JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp);
+JS_GetObjectId(JSContext *cx, JS::HandleObject obj, JS::MutableHandleId idp);
 
 namespace JS {
 
 enum ZoneSpecifier {
     FreshZone = 0,
     SystemZone = 1
 };
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -17,17 +17,16 @@
 #include "jswatchpoint.h"
 #include "jswrapper.h"
 
 #include "gc/Marking.h"
 #ifdef JS_ION
 #include "jit/JitCompartment.h"
 #endif
 #include "js/RootingAPI.h"
-#include "vm/SelfHosting.h"
 #include "vm/StopIterationObject.h"
 #include "vm/WrapperObject.h"
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsgcinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
@@ -52,16 +51,17 @@ JSCompartment::JSCompartment(Zone *zone,
     enterCompartmentDepth(0),
     data(nullptr),
     objectMetadataCallback(nullptr),
     lastAnimationTime(0),
     regExps(runtime_),
     typeReprs(runtime_),
     globalWriteBarriered(false),
     propertyTree(thisForCtor()),
+    selfHostingScriptSource(nullptr),
     gcIncomingGrayPointers(nullptr),
     gcLiveArrayBuffers(nullptr),
     gcWeakMapList(nullptr),
     debugModeBits(runtime_->debugMode ? DebugFromC : 0),
     rngState(0),
     watchpointMap(nullptr),
     scriptCountsMap(nullptr),
     debugScriptMap(nullptr),
@@ -360,22 +360,20 @@ JSCompartment::wrap(JSContext *cx, Mutab
      * we parent all wrappers to the global object in their home compartment.
      * This loses us some transparency, and is generally very cheesy.
      */
     HandleObject global = cx->global();
     RootedObject objGlobal(cx, &obj->global());
     JS_ASSERT(global);
     JS_ASSERT(objGlobal);
 
-    const JSWrapObjectCallbacks *cb;
+    JS_ASSERT(!cx->runtime()->isSelfHostingGlobal(global) &&
+              !cx->runtime()->isSelfHostingGlobal(objGlobal));
 
-    if (cx->runtime()->isSelfHostingGlobal(global) || cx->runtime()->isSelfHostingGlobal(objGlobal))
-        cb = &SelfHostingWrapObjectCallbacks;
-    else
-        cb = cx->runtime()->wrapObjectCallbacks;
+    const JSWrapObjectCallbacks *cb = cx->runtime()->wrapObjectCallbacks;
 
     if (obj->compartment() == this)
         return WrapForSameCompartment(cx, obj, cb);
 
     /* Unwrap the object, but don't unwrap outer windows. */
     unsigned flags = 0;
     obj.set(UncheckedUnwrap(obj, /* stopAtOuter = */ true, &flags));
 
@@ -576,16 +574,22 @@ JSCompartment::sweep(FreeOp *fop, bool r
         sweepInitialShapeTable();
         sweepNewTypeObjectTable(newTypeObjects);
         sweepNewTypeObjectTable(lazyTypeObjects);
         sweepCallsiteClones();
 
         if (global_ && IsObjectAboutToBeFinalized(global_.unsafeGet()))
             global_ = nullptr;
 
+        if (selfHostingScriptSource &&
+            IsObjectAboutToBeFinalized((JSObject **) selfHostingScriptSource.unsafeGet()))
+        {
+            selfHostingScriptSource = nullptr;
+        }
+
 #ifdef JS_ION
         if (jitCompartment_)
             jitCompartment_->sweep(fop);
 #endif
 
         /*
          * JIT code increments activeUseCount for any RegExpShared used by jit
          * code for the lifetime of the JIT script. Thus, we must perform
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -258,16 +258,22 @@ struct JSCompartment
     /*
      * Hash table of all manually call site-cloned functions from within
      * self-hosted code. Cloning according to call site provides extra
      * sensitivity for type specialization and inlining.
      */
     js::CallsiteCloneTable callsiteClones;
     void sweepCallsiteClones();
 
+    /*
+     * Lazily initialized script source object to use for scripts cloned
+     * from the self-hosting global.
+     */
+    js::ReadBarriered<js::ScriptSourceObject> selfHostingScriptSource;
+
     /* During GC, stores the index of this compartment in rt->compartments. */
     unsigned                     gcIndex;
 
     /*
      * During GC, stores the head of a list of incoming pointers from gray cells.
      *
      * The objects in the list are either cross-compartment wrappers, or
      * debugger wrapper objects.  The list link is either in the second extra
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -44,17 +44,16 @@ class JSFunction : public JSObject
         SELF_HOSTED      = 0x0100,  /* function is self-hosted builtin and must not be
                                        decompilable nor constructible. */
         SELF_HOSTED_CTOR = 0x0200,  /* function is self-hosted builtin constructor and
                                        must be constructible but not decompilable. */
         HAS_REST         = 0x0400,  /* function has a rest (...) parameter */
         // 0x0800 is available
         INTERPRETED_LAZY = 0x1000,  /* function is interpreted but doesn't have a script yet */
         ARROW            = 0x2000,  /* ES6 '(args) => body' syntax */
-        SH_WRAPPABLE     = 0x4000,  /* self-hosted function is wrappable, doesn't need to be cloned */
 
         /* Derived Flags values for convenience: */
         NATIVE_FUN = 0,
         INTERPRETED_LAMBDA = INTERPRETED | LAMBDA,
         INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW
     };
 
     static void staticAsserts() {
@@ -122,20 +121,16 @@ class JSFunction : public JSObject
     /* Possible attributes of an interpreted function: */
     bool isFunctionPrototype()      const { return flags() & IS_FUN_PROTO; }
     bool isExprClosure()            const { return flags() & EXPR_CLOSURE; }
     bool hasGuessedAtom()           const { return flags() & HAS_GUESSED_ATOM; }
     bool isLambda()                 const { return flags() & LAMBDA; }
     bool isSelfHostedBuiltin()      const { return flags() & SELF_HOSTED; }
     bool isSelfHostedConstructor()  const { return flags() & SELF_HOSTED_CTOR; }
     bool hasRest()                  const { return flags() & HAS_REST; }
-    bool isWrappable()              const {
-        JS_ASSERT_IF(flags() & SH_WRAPPABLE, isSelfHostedBuiltin());
-        return flags() & SH_WRAPPABLE;
-    }
 
     bool isInterpretedLazy()        const {
         return flags() & INTERPRETED_LAZY;
     }
     bool hasScript()                const {
         return flags() & INTERPRETED;
     }
 
@@ -202,22 +197,16 @@ class JSFunction : public JSObject
         flags_ |= SELF_HOSTED;
     }
 
     void setIsSelfHostedConstructor() {
         JS_ASSERT(!isSelfHostedConstructor());
         flags_ |= SELF_HOSTED_CTOR;
     }
 
-    void makeWrappable() {
-        JS_ASSERT(isSelfHostedBuiltin());
-        JS_ASSERT(!isWrappable());
-        flags_ |= SH_WRAPPABLE;
-    }
-
     void setIsFunctionPrototype() {
         JS_ASSERT(!isFunctionPrototype());
         flags_ |= IS_FUN_PROTO;
     }
 
     // Can be called multiple times by the parser.
     void setIsExprClosure() {
         flags_ |= EXPR_CLOSURE;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3249,39 +3249,52 @@ js_GetClassPrototype(ExclusiveContext *c
         return false;
 
     Value v = global->getPrototype(key);
     if (v.isObject())
         protop.set(&v.toObject());
     return true;
 }
 
-JSProtoKey
-js_IdentifyClassPrototype(JSObject *obj)
-{
-    // First, get the key off the JSClass. This tells us which prototype we
-    // _might_ be. But we still don't know for sure, since the prototype shares
-    // its JSClass with instances.
-    JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
-    if (key == JSProto_Null)
-        return JSProto_Null;
-
-    // Now, see if the cached object matches |obj|.
-    //
-    // Note that standard class objects are cached in the range [0, JSProto_LIMIT),
-    // and the prototypes are cached in [JSProto_LIMIT, 2*JSProto_LIMIT).
+static bool
+IsStandardPrototype(JSObject *obj, JSProtoKey key)
+{
     GlobalObject &global = obj->global();
     Value v = global.getPrototype(key);
-    if (v.isObject() && obj == &v.toObject())
+    return v.isObject() && obj == &v.toObject();
+}
+
+JSProtoKey
+JS::IdentifyStandardInstance(JSObject *obj)
+{
+    // Note: The prototype shares its JSClass with instances.
+    JS_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
+    JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
+    if (key != JSProto_Null && !IsStandardPrototype(obj, key))
         return key;
-
-    // False alarm - just an instance.
     return JSProto_Null;
 }
 
+JSProtoKey
+JS::IdentifyStandardPrototype(JSObject *obj)
+{
+    // Note: The prototype shares its JSClass with instances.
+    JS_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
+    JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
+    if (key != JSProto_Null && IsStandardPrototype(obj, key))
+        return key;
+    return JSProto_Null;
+}
+
+JSProtoKey
+JS::IdentifyStandardInstanceOrPrototype(JSObject *obj)
+{
+    return JSCLASS_CACHED_PROTO_KEY(obj->getClass());
+}
+
 bool
 js_FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp)
 {
     MOZ_ASSERT(clasp);
     JSProtoKey protoKey = GetClassProtoKey(clasp);
     RootedId id(cx);
     if (protoKey != JSProto_Null) {
         JS_ASSERT(JSProto_Null < protoKey);
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1324,23 +1324,16 @@ extern bool
 js_GetClassObject(js::ExclusiveContext *cx, JSProtoKey key,
                   js::MutableHandleObject objp);
 
 extern bool
 js_GetClassPrototype(js::ExclusiveContext *cx, JSProtoKey key,
                      js::MutableHandleObject objp);
 
 /*
- * Determine if the given object is a prototype for a standard class. If so,
- * return the associated JSProtoKey. If not, return JSProto_Null.
- */
-extern JSProtoKey
-js_IdentifyClassPrototype(JSObject *obj);
-
-/*
  * Property-lookup-based access to interface and prototype objects for classes.
  * If the class is built-in (and has a non-null JSProtoKey), these forward to
  * js_GetClass{Object,Prototype}.
  */
 
 bool
 js_FindClassObject(js::ExclusiveContext *cx, js::MutableHandleObject protop,
                    const js::Class *clasp);
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -2538,38 +2538,35 @@ bool
 Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
     if (!policy.allowed())
         return policy.returnValue();
-    if (handler->hasPrototype()) {
-        // If we're using a prototype, we still want to use the proxy trap unless
-        // we have a non-own property with a setter.
-        bool hasOwn;
-        if (!handler->hasOwn(cx, proxy, id, &hasOwn))
-            return false;
-        if (!hasOwn) {
-            RootedObject proto(cx);
-            // Proxies might still use the normal prototype mechanism, rather than
-            // a hook, so query the engine proper
-            if (!JSObject::getProto(cx, proxy, &proto))
-                return false;
-            if (proto) {
-                Rooted<PropertyDescriptor> desc(cx);
-                if (!JS_GetPropertyDescriptorById(cx, proto, id, 0, &desc))
-                    return false;
-                if (desc.object() && desc.setter())
-                    return JSObject::setGeneric(cx, proto, receiver, id, vp, strict);
-            }
-        }
-    }
-    return handler->set(cx, proxy, receiver, id, strict, vp);
+
+    // If the proxy doesn't require that we consult its prototype for the
+    // non-own cases, we can sink to the |set| trap.
+    if (!handler->hasPrototype())
+        return handler->set(cx, proxy, receiver, id, strict, vp);
+
+    // If we have an existing (own or non-own) property with a setter, we want
+    // to invoke that.
+    Rooted<PropertyDescriptor> desc(cx);
+    if (!Proxy::getPropertyDescriptor(cx, proxy, id, &desc, JSRESOLVE_ASSIGNING))
+        return false;
+    if (desc.object() && desc.setter() && desc.setter() != JS_StrictPropertyStub)
+        return CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp);
+
+    // Ok. Either there was no pre-existing property, or it was a value prop
+    // that we're going to shadow. Make a property descriptor and define it.
+    Rooted<PropertyDescriptor> newDesc(cx);
+    newDesc.value().set(vp);
+    return handler->defineProperty(cx, receiver, id, &newDesc);
 }
 
 bool
 Proxy::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     JS_CHECK_RECURSION(cx, return false);
     BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
     AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -24,26 +24,28 @@
 #include "jsgc.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsprf.h"
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jswrapper.h"
 
+#include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/SharedContext.h"
 #include "gc/Marking.h"
 #include "jit/BaselineJIT.h"
 #include "jit/IonCode.h"
 #include "js/OldDebugAPI.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Compression.h"
 #include "vm/Debugger.h"
 #include "vm/Opcodes.h"
+#include "vm/SelfHosting.h"
 #include "vm/Shape.h"
 #include "vm/Xdr.h"
 
 #include "jsfuninlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/ScopeObject-inl.h"
@@ -2780,20 +2782,38 @@ js::CloneScript(JSContext *cx, HandleObj
         HeapPtrObject *vector = src->regexps()->vector;
         for (unsigned i = 0; i < nregexps; i++) {
             JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>());
             if (!clone || !regexps.append(clone))
                 return nullptr;
         }
     }
 
-    /* Wrap the script source object as needed. */
-    RootedObject sourceObject(cx, src->sourceObject());
-    if (!cx->compartment()->wrap(cx, &sourceObject))
-        return nullptr;
+    /*
+     * Wrap the script source object as needed. Self-hosted scripts may be
+     * in another runtime, so lazily create a new script source object to
+     * use for them.
+     */
+    RootedObject sourceObject(cx);
+    if (cx->runtime()->isSelfHostingCompartment(src->compartment())) {
+        if (!cx->compartment()->selfHostingScriptSource) {
+            CompileOptions options(cx);
+            FillSelfHostingCompileOptions(options);
+
+            ScriptSourceObject *obj = frontend::CreateScriptSourceObject(cx, options);
+            if (!obj)
+                return nullptr;
+            cx->compartment()->selfHostingScriptSource = obj;
+        }
+        sourceObject = cx->compartment()->selfHostingScriptSource;
+    } else {
+        sourceObject = src->sourceObject();
+        if (!cx->compartment()->wrap(cx, &sourceObject))
+            return nullptr;
+    }
 
     /* Now that all fallible allocation is complete, create the GC thing. */
 
     CompileOptions options(cx);
     options.setPrincipals(cx->compartment()->principals)
            .setOriginPrincipals(src->originPrincipals())
            .setCompileAndGo(src->compileAndGo())
            .setSelfHostingMode(src->selfHosted())
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -635,17 +635,17 @@ GlobalWorkerThreadState::finishParseTask
          !iter.done();
          iter.next())
     {
         types::TypeObject *object = iter.get<types::TypeObject>();
         TaggedProto proto(object->proto());
         if (!proto.isObject())
             continue;
 
-        JSProtoKey key = js_IdentifyClassPrototype(proto.toObject());
+        JSProtoKey key = JS::IdentifyStandardPrototype(proto.toObject());
         if (key == JSProto_Null)
             continue;
 
         JSObject *newProto = GetClassPrototypePure(&parseTask->scopeChain->global(), key);
         JS_ASSERT(newProto);
 
         object->setProtoUnchecked(newProto);
     }
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -762,21 +762,16 @@ GlobalObject::getSelfHostedFunction(JSCo
                                     unsigned nargs, MutableHandleValue funVal)
 {
     RootedId shId(cx, AtomToId(selfHostedName));
     RootedObject holder(cx, cx->global()->intrinsicsHolder());
 
     if (cx->global()->maybeGetIntrinsicValue(shId, funVal.address()))
         return true;
 
-    if (!cx->runtime()->maybeWrappedSelfHostedFunction(cx, shId, funVal))
-        return false;
-    if (!funVal.isUndefined())
-        return true;
-
     JSFunction *fun = NewFunction(cx, NullPtr(), nullptr, nargs, JSFunction::INTERPRETED_LAZY,
                                   holder, name, JSFunction::ExtendedFinalizeKind, SingletonObject);
     if (!fun)
         return false;
     fun->setIsSelfHostedBuiltin();
     fun->setExtendedSlot(0, StringValue(selfHostedName));
     funVal.setObject(*fun);
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -836,16 +836,20 @@ struct JSRuntime : public JS::shadow::Ru
     /*
      * Both of these allocators are used for regular expression code which is shared at the
      * thread-data level.
      */
     JSC::ExecutableAllocator *execAlloc_;
     WTF::BumpPointerAllocator *bumpAlloc_;
     js::jit::JitRuntime *jitRuntime_;
 
+    /*
+     * Self-hosting state cloned on demand into other compartments. Shared with the parent
+     * runtime if there is one.
+     */
     JSObject *selfHostingGlobal_;
 
     /* Space for interpreter frames. */
     js::InterpreterStack interpreterStack_;
 
     JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx);
     WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx);
     js::jit::JitRuntime *createJitRuntime(JSContext *cx);
@@ -879,25 +883,24 @@ struct JSRuntime : public JS::shadow::Ru
 
     //-------------------------------------------------------------------------
     // Self-hosting support
     //-------------------------------------------------------------------------
 
     bool initSelfHosting(JSContext *cx);
     void finishSelfHosting();
     void markSelfHostingGlobal(JSTracer *trc);
-    bool isSelfHostingGlobal(js::HandleObject global) {
+    bool isSelfHostingGlobal(JSObject *global) {
         return global == selfHostingGlobal_;
     }
+    bool isSelfHostingCompartment(JSCompartment *comp);
     bool cloneSelfHostedFunctionScript(JSContext *cx, js::Handle<js::PropertyName*> name,
                                        js::Handle<JSFunction*> targetFun);
     bool cloneSelfHostedValue(JSContext *cx, js::Handle<js::PropertyName*> name,
                               js::MutableHandleValue vp);
-    bool maybeWrappedSelfHostedFunction(JSContext *cx, js::HandleId name,
-                                        js::MutableHandleValue funVal);
 
     //-------------------------------------------------------------------------
     // Locale information
     //-------------------------------------------------------------------------
 
     /*
      * Set the default locale for the ECMAScript Internationalization API
      * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -159,28 +159,16 @@ intrinsic_MakeConstructible(JSContext *c
         return false;
     }
 
     ctor->as<JSFunction>().setIsSelfHostedConstructor();
     args.rval().setUndefined();
     return true;
 }
 
-static bool
-intrinsic_MakeWrappable(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    JS_ASSERT(args.length() >= 1);
-    JS_ASSERT(args[0].isObject());
-    JS_ASSERT(args[0].toObject().is<JSFunction>());
-    args[0].toObject().as<JSFunction>().makeWrappable();
-    args.rval().setUndefined();
-    return true;
-}
-
 /*
  * Used to decompile values in the nearest non-builtin stack frame, falling
  * back to decompiling in the current frame. Helpful for printing higher-order
  * function arguments.
  *
  * The user must supply the argument number of the value in question; it
  * _cannot_ be automatically determined.
  */
@@ -657,17 +645,16 @@ intrinsic_RuntimeDefaultLocale(JSContext
 static const JSFunctionSpec intrinsic_functions[] = {
     JS_FN("ToObject",                intrinsic_ToObject,                1,0),
     JS_FN("ToInteger",               intrinsic_ToInteger,               1,0),
     JS_FN("IsCallable",              intrinsic_IsCallable,              1,0),
     JS_FN("ThrowError",              intrinsic_ThrowError,              4,0),
     JS_FN("AssertionFailed",         intrinsic_AssertionFailed,         1,0),
     JS_FN("SetScriptHints",          intrinsic_SetScriptHints,          2,0),
     JS_FN("MakeConstructible",       intrinsic_MakeConstructible,       1,0),
-    JS_FN("MakeWrappable",           intrinsic_MakeWrappable,           1,0),
     JS_FN("DecompileArg",            intrinsic_DecompileArg,            2,0),
     JS_FN("RuntimeDefaultLocale",    intrinsic_RuntimeDefaultLocale,    0,0),
 
     JS_FN("UnsafePutElements",       intrinsic_UnsafePutElements,       3,0),
     JS_FN("UnsafeSetReservedSlot",   intrinsic_UnsafeSetReservedSlot,   3,0),
     JS_FN("UnsafeGetReservedSlot",   intrinsic_UnsafeGetReservedSlot,   2,0),
     JS_FN("HaveSameClass",           intrinsic_HaveSameClass,           2,0),
     JS_FN("IsPackedArray",           intrinsic_IsPackedArray,           1,0),
@@ -772,21 +759,62 @@ static const JSFunctionSpec intrinsic_fu
     JS_FNINFO("ParallelSpew",
               JSNativeThreadSafeWrapper<intrinsic_ParallelSpew>,
               &intrinsic_ParallelSpew_jitInfo, 1,0),
 #endif
 
     JS_FS_END
 };
 
+void
+js::FillSelfHostingCompileOptions(CompileOptions &options)
+{
+    /*
+     * In self-hosting mode, scripts emit JSOP_CALLINTRINSIC instead of
+     * JSOP_NAME or JSOP_GNAME to access unbound variables. JSOP_CALLINTRINSIC
+     * does a name lookup in a special object, whose properties are filled in
+     * lazily upon first access for a given global.
+     *
+     * As that object is inaccessible to client code, the lookups are
+     * guaranteed to return the original objects, ensuring safe implementation
+     * of self-hosted builtins.
+     *
+     * Additionally, the special syntax callFunction(fun, receiver, ...args)
+     * is supported, for which bytecode is emitted that invokes |fun| with
+     * |receiver| as the this-object and ...args as the arguments.
+     */
+    options.setFileAndLine("self-hosted", 1);
+    options.setSelfHostingMode(true);
+    options.setCanLazilyParse(false);
+    options.setSourcePolicy(CompileOptions::NO_SOURCE);
+    options.setVersion(JSVERSION_LATEST);
+    options.werrorOption = true;
+
+#ifdef DEBUG
+    options.strictOption = true;
+    options.extraWarningsOption = true;
+#endif
+}
+
 bool
 JSRuntime::initSelfHosting(JSContext *cx)
 {
     JS_ASSERT(!selfHostingGlobal_);
 
+    if (cx->runtime()->parentRuntime) {
+        selfHostingGlobal_ = cx->runtime()->parentRuntime->selfHostingGlobal_;
+        return true;
+    }
+
+    /*
+     * Self hosted state can be accessed from threads for other runtimes
+     * parented to this one, so cannot include state in the nursery.
+     */
+    JS::AutoDisableGenerationalGC disable(cx->runtime());
+
     bool receivesDefaultObject = !cx->options().noDefaultCompartmentObject();
     RootedObject savedGlobal(cx, receivesDefaultObject
                                  ? js::DefaultObjectForContextOrNull(cx)
                                  : nullptr);
     if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class,
                                                   nullptr, JS::DontFireOnNewGlobalHook)))
         return false;
     JSAutoCompartment ac(cx, selfHostingGlobal_);
@@ -803,42 +831,18 @@ JSRuntime::initSelfHosting(JSContext *cx
     if (!GlobalObject::initStandardClasses(cx, shg))
         return false;
 
     if (!JS_DefineFunctions(cx, shg, intrinsic_functions))
         return false;
 
     JS_FireOnNewGlobalObject(cx, shg);
 
-    /*
-     * In self-hosting mode, scripts emit JSOP_CALLINTRINSIC instead of
-     * JSOP_NAME or JSOP_GNAME to access unbound variables. JSOP_CALLINTRINSIC
-     * does a name lookup in a special object, whose properties are filled in
-     * lazily upon first access for a given global.
-     *
-     * As that object is inaccessible to client code, the lookups are
-     * guaranteed to return the original objects, ensuring safe implementation
-     * of self-hosted builtins.
-     *
-     * Additionally, the special syntax _CallFunction(receiver, ...args, fun)
-     * is supported, for which bytecode is emitted that invokes |fun| with
-     * |receiver| as the this-object and ...args as the arguments..
-     */
     CompileOptions options(cx);
-    options.setFileAndLine("self-hosted", 1);
-    options.setSelfHostingMode(true);
-    options.setCanLazilyParse(false);
-    options.setSourcePolicy(CompileOptions::NO_SOURCE);
-    options.setVersion(JSVERSION_LATEST);
-    options.werrorOption = true;
-
-#ifdef DEBUG
-    options.strictOption = true;
-    options.extraWarningsOption = true;
-#endif
+    FillSelfHostingCompileOptions(options);
 
     /*
      * Set a temporary error reporter printing to stderr because it is too
      * early in the startup process for any other reporter to be registered
      * and we don't want errors in self-hosted code to be silently swallowed.
      */
     JSErrorReporter oldReporter = JS_SetErrorReporter(cx, selfHosting_ErrorReporter);
     RootedValue rv(cx);
@@ -877,163 +881,202 @@ void
 JSRuntime::finishSelfHosting()
 {
     selfHostingGlobal_ = nullptr;
 }
 
 void
 JSRuntime::markSelfHostingGlobal(JSTracer *trc)
 {
-    if (selfHostingGlobal_)
+    if (selfHostingGlobal_ && !parentRuntime)
         MarkObjectRoot(trc, &selfHostingGlobal_, "self-hosting global");
 }
 
-typedef AutoObjectObjectHashMap CloneMemory;
-static bool CloneValue(JSContext *cx, MutableHandleValue vp, CloneMemory &clonedObjects);
+bool
+JSRuntime::isSelfHostingCompartment(JSCompartment *comp)
+{
+    return selfHostingGlobal_->compartment() == comp;
+}
+
+// CloneMemory maps objects to each other which may be in different
+// runtimes. This class should only be used within an AutoSuppressGC,
+// so that issues of managing which objects should be traced can be ignored.
+typedef HashMap<JSObject *, JSObject *> CloneMemory;
+
+static bool
+CloneValue(JSContext *cx, const Value &selfHostedValue, MutableHandleValue vp, CloneMemory &clonedObjects);
 
 static bool
-GetUnclonedValue(JSContext *cx, Handle<JSObject*> src, HandleId id, MutableHandleValue vp)
+GetUnclonedValue(JSContext *cx, JSObject *selfHostedObject, jsid id, Value *vp)
 {
-    AutoCompartment ac(cx, src);
-    return JSObject::getGeneric(cx, src, src, id, vp);
+    *vp = UndefinedValue();
+
+    if (JSID_IS_INT(id)) {
+        size_t index = JSID_TO_INT(id);
+        if (index < selfHostedObject->getDenseInitializedLength() &&
+            !selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE))
+        {
+            *vp = selfHostedObject->getDenseElement(JSID_TO_INT(id));
+            return true;
+        }
+    }
+
+    // Since all atoms used by self hosting are marked as permanent, any
+    // attempt to look up a non-permanent atom will fail. We should only
+    // see such atoms when code is looking for properties on the self
+    // hosted global which aren't present.
+    if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) {
+        JS_ASSERT(selfHostedObject->is<GlobalObject>());
+        gc::AutoSuppressGC suppress(cx);
+        JS_ReportError(cx, "No such property on self hosted object");
+        return false;
+    }
+
+    Shape *shape = selfHostedObject->nativeLookupPure(id);
+    if (!shape) {
+        gc::AutoSuppressGC suppress(cx);
+        JS_ReportError(cx, "No such property on self hosted object");
+        return false;
+    }
+
+    JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());
+    *vp = selfHostedObject->getSlot(shape->slot());
+    return true;
 }
 
 static bool
-CloneProperties(JSContext *cx, HandleObject obj, HandleObject clone, CloneMemory &clonedObjects)
+CloneProperties(JSContext *cx, JSObject *selfHostedObject,
+                HandleObject clone, CloneMemory &clonedObjects)
 {
+    Vector<jsid> ids(cx);
+
+    for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) {
+        if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
+            if (!ids.append(INT_TO_JSID(i)))
+                return false;
+        }
+    }
+
+    for (Shape::Range<NoGC> range(selfHostedObject->lastProperty()); !range.empty(); range.popFront()) {
+        Shape &shape = range.front();
+        if (shape.enumerable() && !ids.append(shape.propid()))
+            return false;
+    }
+
     RootedId id(cx);
     RootedValue val(cx);
-    AutoIdVector ids(cx);
-    {
-        AutoCompartment ac(cx, obj);
-        if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &ids))
-            return false;
-    }
     for (uint32_t i = 0; i < ids.length(); i++) {
         id = ids[i];
-        if (!GetUnclonedValue(cx, obj, id, &val) ||
-            !CloneValue(cx, &val, clonedObjects) ||
+        Value selfHostedValue;
+        if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue))
+            return false;
+        if (!CloneValue(cx, selfHostedValue, &val, clonedObjects) ||
             !JS_DefinePropertyById(cx, clone, id, val.get(), nullptr, nullptr, 0))
         {
             return false;
         }
     }
 
     return true;
 }
 
-static gc::AllocKind
-GetObjectAllocKindForClone(JSRuntime *rt, JSObject *obj)
+static JSObject *
+CloneObject(JSContext *cx, JSObject *selfHostedObject, CloneMemory &clonedObjects)
 {
-    if (!gc::IsInsideNursery(rt, (void *)obj))
-        return obj->tenuredGetAllocKind();
-
-    if (obj->is<JSFunction>())
-        return obj->as<JSFunction>().getAllocKind();
-
-    gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(obj->numFixedSlots());
-    if (CanBeFinalizedInBackground(kind, obj->getClass()))
-        kind = GetBackgroundAllocKind(kind);
-    return kind;
-}
-
-static JSObject *
-CloneObject(JSContext *cx, HandleObject srcObj, CloneMemory &clonedObjects)
-{
-    DependentAddPtr<CloneMemory> p(cx, clonedObjects, srcObj.get());
+    DependentAddPtr<CloneMemory> p(cx, clonedObjects, selfHostedObject);
     if (p)
         return p->value();
     RootedObject clone(cx);
-    if (srcObj->is<JSFunction>()) {
-        if (srcObj->as<JSFunction>().isWrappable()) {
-            clone = srcObj;
-            if (!cx->compartment()->wrap(cx, &clone))
-                return nullptr;
-        } else {
-            RootedFunction fun(cx, &srcObj->as<JSFunction>());
-            bool hasName = fun->atom() != nullptr;
-            js::gc::AllocKind kind = hasName
-                                     ? JSFunction::ExtendedFinalizeKind
-                                     : fun->getAllocKind();
-            clone = CloneFunctionObject(cx, fun, cx->global(), kind, TenuredObject);
-            // To be able to re-lazify the cloned function, its name in the
-            // self-hosting compartment has to be stored on the clone.
-            if (clone && hasName)
-                clone->as<JSFunction>().setExtendedSlot(0, StringValue(fun->atom()));
-        }
-    } else if (srcObj->is<RegExpObject>()) {
-        RegExpObject &reobj = srcObj->as<RegExpObject>();
+    if (selfHostedObject->is<JSFunction>()) {
+        JSFunction *selfHostedFunction = &selfHostedObject->as<JSFunction>();
+        bool hasName = selfHostedFunction->atom() != nullptr;
+        js::gc::AllocKind kind = hasName
+                                 ? JSFunction::ExtendedFinalizeKind
+                                 : selfHostedFunction->getAllocKind();
+        clone = CloneFunctionObject(cx, HandleFunction::fromMarkedLocation(&selfHostedFunction),
+                                    cx->global(), kind, TenuredObject);
+        // To be able to re-lazify the cloned function, its name in the
+        // self-hosting compartment has to be stored on the clone.
+        if (clone && hasName)
+            clone->as<JSFunction>().setExtendedSlot(0, StringValue(selfHostedFunction->atom()));
+    } else if (selfHostedObject->is<RegExpObject>()) {
+        RegExpObject &reobj = selfHostedObject->as<RegExpObject>();
         RootedAtom source(cx, reobj.getSource());
+        JS_ASSERT(source->isPermanentAtom());
         clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), nullptr);
-    } else if (srcObj->is<DateObject>()) {
-        clone = JS_NewDateObjectMsec(cx, srcObj->as<DateObject>().UTCTime().toNumber());
-    } else if (srcObj->is<BooleanObject>()) {
-        clone = BooleanObject::create(cx, srcObj->as<BooleanObject>().unbox());
-    } else if (srcObj->is<NumberObject>()) {
-        clone = NumberObject::create(cx, srcObj->as<NumberObject>().unbox());
-    } else if (srcObj->is<StringObject>()) {
-        Rooted<JSFlatString*> str(cx, srcObj->as<StringObject>().unbox()->ensureFlat(cx));
-        if (!str)
-            return nullptr;
-        str = js_NewStringCopyN<CanGC>(cx, str->chars(), str->length());
+    } else if (selfHostedObject->is<DateObject>()) {
+        clone = JS_NewDateObjectMsec(cx, selfHostedObject->as<DateObject>().UTCTime().toNumber());
+    } else if (selfHostedObject->is<BooleanObject>()) {
+        clone = BooleanObject::create(cx, selfHostedObject->as<BooleanObject>().unbox());
+    } else if (selfHostedObject->is<NumberObject>()) {
+        clone = NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox());
+    } else if (selfHostedObject->is<StringObject>()) {
+        JSString *selfHostedString = selfHostedObject->as<StringObject>().unbox();
+        if (!selfHostedString->isFlat())
+            MOZ_CRASH();
+        RootedString str(cx, js_NewStringCopyN<CanGC>(cx,
+                                                      selfHostedString->asFlat().chars(),
+                                                      selfHostedString->asFlat().length()));
         if (!str)
             return nullptr;
         clone = StringObject::create(cx, str);
-    } else if (srcObj->is<ArrayObject>()) {
+    } else if (selfHostedObject->is<ArrayObject>()) {
         clone = NewDenseEmptyArray(cx, nullptr, TenuredObject);
     } else {
-        JS_ASSERT(srcObj->isNative());
-        clone = NewObjectWithGivenProto(cx, srcObj->getClass(), nullptr, cx->global(),
-                                        GetObjectAllocKindForClone(cx->runtime(), srcObj),
+        JS_ASSERT(selfHostedObject->isNative());
+        clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), nullptr, cx->global(),
+                                        selfHostedObject->tenuredGetAllocKind(),
                                         SingletonObject);
     }
     if (!clone)
         return nullptr;
-    if (!p.add(cx, clonedObjects, srcObj, clone))
+    if (!p.add(cx, clonedObjects, selfHostedObject, clone))
         return nullptr;
-    if (!CloneProperties(cx, srcObj, clone, clonedObjects)) {
-        clonedObjects.remove(srcObj);
+    if (!CloneProperties(cx, selfHostedObject, clone, clonedObjects)) {
+        clonedObjects.remove(selfHostedObject);
         return nullptr;
     }
     return clone;
 }
 
 static bool
-CloneValue(JSContext *cx, MutableHandleValue vp, CloneMemory &clonedObjects)
+CloneValue(JSContext *cx, const Value &selfHostedValue, MutableHandleValue vp, CloneMemory &clonedObjects)
 {
-    if (vp.isObject()) {
-        RootedObject obj(cx, &vp.toObject());
-        RootedObject clone(cx, CloneObject(cx, obj, clonedObjects));
+    if (selfHostedValue.isObject()) {
+        JSObject *selfHostedObject = &selfHostedValue.toObject();
+        RootedObject clone(cx, CloneObject(cx, selfHostedObject, clonedObjects));
         if (!clone)
             return false;
         vp.setObject(*clone);
-    } else if (vp.isBoolean() || vp.isNumber() || vp.isNullOrUndefined()) {
-        // Nothing to do here: these are represented inline in the value
-    } else if (vp.isString()) {
-        Rooted<JSFlatString*> str(cx, vp.toString()->ensureFlat(cx));
-        if (!str)
-            return false;
-        RootedString clone(cx, js_NewStringCopyN<CanGC>(cx, str->chars(), str->length()));
+    } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) {
+        // Nothing to do here: these are represented inline in the value.
+        vp.set(selfHostedValue);
+    } else if (selfHostedValue.isString()) {
+        if (!selfHostedValue.toString()->isFlat())
+            MOZ_CRASH();
+        JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat();
+        RootedString clone(cx, js_NewStringCopyN<CanGC>(cx,
+                                                        selfHostedString->chars(),
+                                                        selfHostedString->length()));
         if (!clone)
             return false;
         vp.setString(clone);
     } else {
         MOZ_ASSUME_UNREACHABLE("Self-hosting CloneValue can't clone given value.");
     }
     return true;
 }
 
 bool
 JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle<PropertyName*> name,
                                          Handle<JSFunction*> targetFun)
 {
-    RootedObject shg(cx, selfHostingGlobal_);
-    RootedValue funVal(cx);
     RootedId id(cx, NameToId(name));
-    if (!GetUnclonedValue(cx, shg, id, &funVal))
+    Value funVal;
+    if (!GetUnclonedValue(cx, selfHostingGlobal_, id, &funVal))
         return false;
 
     RootedFunction sourceFun(cx, &funVal.toObject().as<JSFunction>());
     // JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
     // aren't any.
     JS_ASSERT(!sourceFun->isGenerator());
     RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx));
     if (!sourceScript)
@@ -1051,109 +1094,35 @@ JSRuntime::cloneSelfHostedFunctionScript
     targetFun->setScript(cscript);
     JS_ASSERT(targetFun->isExtended());
     return true;
 }
 
 bool
 JSRuntime::cloneSelfHostedValue(JSContext *cx, Handle<PropertyName*> name, MutableHandleValue vp)
 {
-    RootedObject shg(cx, selfHostingGlobal_);
-    RootedValue val(cx);
     RootedId id(cx, NameToId(name));
-    if (!GetUnclonedValue(cx, shg, id, &val))
-         return false;
+    Value selfHostedValue;
+    if (!GetUnclonedValue(cx, selfHostingGlobal_, id, &selfHostedValue))
+        return false;
 
     /*
      * We don't clone if we're operating in the self-hosting global, as that
      * means we're currently executing the self-hosting script while
      * initializing the runtime (see JSRuntime::initSelfHosting).
      */
     if (cx->global() != selfHostingGlobal_) {
+        gc::AutoSuppressGC suppress(cx);
         CloneMemory clonedObjects(cx);
-        if (!clonedObjects.init() || !CloneValue(cx, &val, clonedObjects))
+        if (!clonedObjects.init() || !CloneValue(cx, selfHostedValue, vp, clonedObjects))
             return false;
-    }
-    vp.set(val);
-    return true;
-}
-
-class OpaqueWrapper : public CrossCompartmentSecurityWrapper
-{
-  public:
-    OpaqueWrapper() : CrossCompartmentSecurityWrapper(0) {}
-    virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id,
-                       Wrapper::Action act, bool *bp) MOZ_OVERRIDE
-    {
-        *bp = false;
-        return false;
-    }
-    static OpaqueWrapper singleton;
-};
-
-OpaqueWrapper OpaqueWrapper::singleton;
-
-class OpaqueWrapperWithCall : public OpaqueWrapper
-{
-  public:
-    OpaqueWrapperWithCall() : OpaqueWrapper() {}
-    virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id,
-                       Wrapper::Action act, bool *bp) MOZ_OVERRIDE
-    {
-        if (act != Wrapper::CALL) {
-            *bp = false;
-            return false;
-        }
-        return true;
+    } else {
+        vp.set(selfHostedValue);
     }
-    static OpaqueWrapperWithCall singleton;
-};
-
-OpaqueWrapperWithCall OpaqueWrapperWithCall::singleton;
-
-static JSObject *
-SelfHostingWrapObjectCallback(JSContext *cx, HandleObject existing, HandleObject obj,
-                              HandleObject proto, HandleObject parent, unsigned flags)
-{
-    RootedObject objGlobal(cx, &obj->global());
-    bool wrappingSelfHostedFunction = cx->runtime()->isSelfHostingGlobal(objGlobal);
-    JS_ASSERT_IF(!wrappingSelfHostedFunction, cx->runtime()->isSelfHostingGlobal(cx->global()));
-
-    OpaqueWrapper *handler = wrappingSelfHostedFunction
-                             ? &OpaqueWrapperWithCall::singleton
-                             : &OpaqueWrapper::singleton;
-    if (existing)
-        return Wrapper::Renew(cx, existing, obj, handler);
-    else
-        return Wrapper::New(cx, obj, parent, handler);
-}
-
-const JSWrapObjectCallbacks
-js::SelfHostingWrapObjectCallbacks = {
-    SelfHostingWrapObjectCallback,
-    nullptr,
-    nullptr
-};
-
-bool
-JSRuntime::maybeWrappedSelfHostedFunction(JSContext *cx, HandleId id, MutableHandleValue funVal)
-{
-    RootedObject shg(cx, selfHostingGlobal_);
-    if (!GetUnclonedValue(cx, shg, id, funVal))
-        return false;
-
-    JS_ASSERT(funVal.isObject());
-    JS_ASSERT(funVal.toObject().isCallable());
-
-    if (!funVal.toObject().as<JSFunction>().isWrappable()) {
-        funVal.setUndefined();
-        return true;
-    }
-
-    return cx->compartment()->wrap(cx, funVal);
+    return true;
 }
 
 JSFunction *
 js::SelfHostedFunction(JSContext *cx, HandlePropertyName propName)
 {
     RootedValue func(cx);
     if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func))
         return nullptr;
--- a/js/src/vm/SelfHosting.h
+++ b/js/src/vm/SelfHosting.h
@@ -9,25 +9,20 @@
 
 #include "jsapi.h"
 
 class JSAtom;
 
 namespace js {
 
 /*
- * When wrapping objects for use by self-hosted code, we skip all checks and
- * always create an OpaqueWrapper that allows nothing.
- * When wrapping functions from the self-hosting compartment for use in other
- * compartments, we create an OpaqueWrapperWithCall that only allows calls,
- * nothing else.
- */
-extern const JSWrapObjectCallbacks SelfHostingWrapObjectCallbacks;
-
-/*
  * Check whether the given JSFunction is a self-hosted function whose
  * self-hosted name is the given name.
  */
 bool IsSelfHostedFunctionWithName(JSFunction *fun, JSAtom *name);
 
+/* Get the compile options used when compiling self hosted code. */
+void
+FillSelfHostingCompileOptions(JS::CompileOptions &options);
+
 } /* namespace js */
 
 #endif /* vm_SelfHosting_h_ */
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -200,17 +200,17 @@ AccessCheck::isCrossOriginAccessPermitte
 
     // For XOWs, we generally want to deny enumerate-like operations, but fail
     // silently (see CrossOriginAccessiblePropertiesOnly::deny).
     if (act == Wrapper::ENUMERATE)
         return false;
 
     const char *name;
     const js::Class *clasp = js::GetObjectClass(obj);
-    MOZ_ASSERT(Jsvalify(clasp) != &XrayUtils::HolderClass, "shouldn't have a holder here");
+    MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(Jsvalify(clasp)), "shouldn't have a holder here");
     if (clasp->ext.innerObject)
         name = "Window";
     else
         name = clasp->name;
 
     if (JSID_IS_STRING(id)) {
         if (IsPermitted(name, JSID_TO_FLAT_STRING(id), act == Wrapper::SET))
             return true;
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -31,17 +31,17 @@ AllowedByBase(JSContext *cx, HandleObjec
 }
 
 static bool
 PropIsFromStandardPrototype(JSContext *cx, JS::MutableHandle<JSPropertyDescriptor> desc)
 {
     MOZ_ASSERT(desc.object());
     RootedObject unwrapped(cx, js::UncheckedUnwrap(desc.object()));
     JSAutoCompartment ac(cx, unwrapped);
-    return JS_IdentifyClassPrototype(unwrapped) != JSProto_Null;
+    return IdentifyStandardPrototype(unwrapped) != JSProto_Null;
 }
 
 // Note that we're past the policy enforcement stage, here, so we can query
 // ChromeObjectWrapperBase and get an unfiltered view of the underlying object.
 // This lets us determine whether the property we would have found (given a
 // transparent wrapper) would have come off a standard prototype.
 static bool
 PropIsFromStandardPrototype(JSContext *cx, HandleObject wrapper,
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -169,17 +169,17 @@ WrapperFactory::PrepareForWrapping(JSCon
     // subsumes call below.
     bool subsumes = AccessCheck::subsumes(js::GetContextCompartment(cx),
                                           js::GetObjectCompartment(obj));
     XrayType xrayType = GetXrayType(obj);
     if (!subsumes && xrayType == NotXray) {
         JSProtoKey key = JSProto_Null;
         {
             JSAutoCompartment ac(cx, obj);
-            key = JS_IdentifyClassPrototype(obj);
+            key = IdentifyStandardPrototype(obj);
         }
         if (key != JSProto_Null) {
             RootedObject homeProto(cx);
             if (!JS_GetClassPrototype(cx, key, &homeProto))
                 return nullptr;
             MOZ_ASSERT(homeProto);
             // No need to double-wrap here. We should never have waivers to
             // COWs.
@@ -369,17 +369,17 @@ JSObject *
 WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj,
                        HandleObject wrappedProto, HandleObject parent,
                        unsigned flags)
 {
     MOZ_ASSERT(!IsWrapper(obj) ||
                GetProxyHandler(obj) == &XrayWaiver ||
                js::GetObjectClass(obj)->ext.innerObject,
                "wrapped object passed to rewrap");
-    MOZ_ASSERT(JS_GetClass(obj) != &XrayUtils::HolderClass, "trying to wrap a holder");
+    MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(JS_GetClass(obj)), "trying to wrap a holder");
     MOZ_ASSERT(!js::IsInnerObject(obj));
     // We sometimes end up here after nsContentUtils has been shut down but before
     // XPConnect has been shut down, so check the context stack the roundabout way.
     MOZ_ASSERT(XPCJSRuntime::Get()->GetJSContextStack()->Peek() == cx);
 
     // Compute the information we need to select the right wrapper.
     JSCompartment *origin = js::GetObjectCompartment(obj);
     JSCompartment *target = js::GetContextCompartment(cx);
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -32,44 +32,33 @@ using namespace mozilla;
 using js::Wrapper;
 using js::BaseProxyHandler;
 using js::IsCrossCompartmentWrapper;
 using js::UncheckedUnwrap;
 using js::CheckedUnwrap;
 
 namespace xpc {
 
-static const uint32_t JSSLOT_RESOLVING = 0;
-
-namespace XrayUtils {
-
-const JSClass HolderClass = {
-    "NativePropertyHolder",
-    JSCLASS_HAS_RESERVED_SLOTS(2),
-    JS_PropertyStub,        JS_DeletePropertyStub, holder_get,      holder_set,
-    JS_EnumerateStub,       JS_ResolveStub,  JS_ConvertStub
-};
-}
-
 using namespace XrayUtils;
 
 XrayType
 GetXrayType(JSObject *obj)
 {
     obj = js::UncheckedUnwrap(obj, /* stopAtOuter = */ false);
     if (mozilla::dom::UseDOMXray(obj))
         return XrayForDOMObject;
 
     const js::Class* clasp = js::GetObjectClass(obj);
     if (IS_WN_CLASS(clasp) || clasp->ext.innerObject)
         return XrayForWrappedNative;
 
     return NotXray;
 }
 
+const uint32_t JSSLOT_RESOLVING = 0;
 ResolvingId::ResolvingId(JSContext *cx, HandleObject wrapper, HandleId id)
   : mId(id),
     mHolder(cx, getHolderObject(wrapper)),
     mPrev(getResolvingId(mHolder)),
     mXrayShadowing(false)
 {
     js::SetReservedSlot(mHolder, JSSLOT_RESOLVING, js::PrivateValue(this));
 }
@@ -188,16 +177,20 @@ private:
     JSObject* attachExpandoObject(JSContext *cx, HandleObject target,
                                   nsIPrincipal *origin,
                                   HandleObject exclusiveGlobal);
 };
 
 class XPCWrappedNativeXrayTraits : public XrayTraits
 {
 public:
+    enum {
+        HasPrototype = 0
+    };
+
     static const XrayType Type = XrayForWrappedNative;
 
     virtual bool resolveNativeProperty(JSContext *cx, HandleObject wrapper,
                                        HandleObject holder, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
     virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
                                     HandleObject holder, HandleId id,
                                     MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
@@ -222,22 +215,33 @@ public:
     }
 
     virtual void preserveWrapper(JSObject *target);
 
     typedef ResolvingId ResolvingIdImpl;
 
     virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
 
+    static const JSClass HolderClass;
     static XPCWrappedNativeXrayTraits singleton;
 };
 
+const JSClass XPCWrappedNativeXrayTraits::HolderClass = {
+    "NativePropertyHolder", JSCLASS_HAS_RESERVED_SLOTS(2),
+    JS_PropertyStub, JS_DeletePropertyStub, holder_get, holder_set,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
+};
+
 class DOMXrayTraits : public XrayTraits
 {
 public:
+    enum {
+        HasPrototype = 0
+    };
+
     static const XrayType Type = XrayForDOMObject;
 
     virtual bool resolveNativeProperty(JSContext *cx, HandleObject wrapper,
                                        HandleObject holder, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
     virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
                                     HandleObject holder, HandleId id,
                                     MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
@@ -522,16 +526,27 @@ XPCWrappedNativeXrayTraits::isResolving(
                                         jsid id)
 {
     ResolvingId *cur = ResolvingId::getResolvingId(holder);
     if (!cur)
         return false;
     return cur->isResolving(id);
 }
 
+namespace XrayUtils {
+
+bool
+IsXPCWNHolderClass(const JSClass *clasp)
+{
+  return clasp == &XPCWrappedNativeXrayTraits::HolderClass;
+}
+
+}
+
+
 // Some DOM objects have shared properties that don't have an explicit
 // getter/setter and rely on the class getter/setter. We install a
 // class getter/setter on the holder object to trigger them.
 bool
 holder_get(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandleValue vp)
 {
     // JSClass::getProperty is wacky enough that it's hard to be sure someone
     // can't inherit this getter by prototyping a random object to an
@@ -864,16 +879,35 @@ XrayTraits::resolveOwnProperty(JSContext
 
     if (found) {
         if (!JS_WrapPropertyDescriptor(cx, desc))
             return false;
         // Pretend the property lives on the wrapper.
         desc.object().set(wrapper);
         return true;
     }
+
+    // Handle .wrappedJSObject for subsuming callers. This should move once we
+    // sort out own-ness for the holder.
+    if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_WRAPPED_JSOBJECT) &&
+        AccessCheck::wrapperSubsumes(wrapper))
+    {
+        if (!JS_AlreadyHasOwnPropertyById(cx, holder, id, &found))
+            return false;
+        if (!found && !JS_DefinePropertyById(cx, holder, id, UndefinedValue(),
+                                             wrappedJSObject_getter, nullptr,
+                                             JSPROP_ENUMERATE | JSPROP_SHARED)) {
+            return false;
+        }
+        if (!JS_GetPropertyDescriptorById(cx, holder, id, 0, desc))
+            return false;
+        desc.object().set(wrapper);
+        return true;
+    }
+
     return true;
 }
 
 bool
 XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
                                                HandleObject wrapper, HandleObject holder,
                                                HandleId id, MutableHandle<JSPropertyDescriptor> desc,
                                                unsigned flags)
@@ -1234,16 +1268,17 @@ DOMXrayTraits::createHolder(JSContext *c
     RootedObject global(cx, JS_GetGlobalForObject(cx, wrapper));
     return JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr(), global);
 }
 
 template <typename Base, typename Traits>
 XrayWrapper<Base, Traits>::XrayWrapper(unsigned flags)
   : Base(flags | WrapperFactory::IS_XRAY_WRAPPER_FLAG)
 {
+    Base::setHasPrototype(Traits::HasPrototype);
 }
 
 template <typename Base, typename Traits>
 XrayWrapper<Base, Traits>::~XrayWrapper()
 {
 }
 
 namespace XrayUtils {
@@ -1437,30 +1472,16 @@ XrayWrapper<Base, Traits>::getPropertyDe
         return true;
     }
 
     typename Traits::ResolvingIdImpl resolving(cx, wrapper, id);
 
     if (!holder)
         return false;
 
-    // Only chrome wrappers and same-origin xrays (used by jetpack sandboxes)
-    // get .wrappedJSObject. We can check this by determining if the compartment
-    // of the wrapper subsumes that of the wrappee.
-    XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
-    if (AccessCheck::wrapperSubsumes(wrapper) &&
-        id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) {
-        desc.object().set(wrapper);
-        desc.setAttributes(JSPROP_ENUMERATE|JSPROP_SHARED);
-        desc.setGetter(wrappedJSObject_getter);
-        desc.setSetter(nullptr);
-        desc.value().set(JSVAL_VOID);
-        return true;
-    }
-
     // Ordering is important here.
     //
     // We first need to call resolveOwnProperty, even before checking the holder,
     // because there might be a new dynamic |own| property that appears and
     // shadows a previously-resolved non-own property that we cached on the
     // holder. This can happen with indexed properties on NodeLists, for example,
     // which are |own| value props.
     //
@@ -1763,29 +1784,29 @@ template <typename Base, typename Traits
 bool
 XrayWrapper<Base, Traits>::get(JSContext *cx, HandleObject wrapper,
                                HandleObject receiver, HandleId id,
                                MutableHandleValue vp)
 {
     // Skip our Base if it isn't already ProxyHandler.
     // NB: None of the functions we call are prepared for the receiver not
     // being the wrapper, so ignore the receiver here.
-    return js::BaseProxyHandler::get(cx, wrapper, wrapper, id, vp);
+    return js::BaseProxyHandler::get(cx, wrapper, Traits::HasPrototype ? receiver : wrapper, id, vp);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::set(JSContext *cx, HandleObject wrapper,
                                HandleObject receiver, HandleId id,
                                bool strict, MutableHandleValue vp)
 {
     // Skip our Base if it isn't already BaseProxyHandler.
     // NB: None of the functions we call are prepared for the receiver not
     // being the wrapper, so ignore the receiver here.
-    return js::BaseProxyHandler::set(cx, wrapper, wrapper, id, strict, vp);
+    return js::BaseProxyHandler::set(cx, wrapper, Traits::HasPrototype ? receiver : wrapper, id, strict, vp);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::has(JSContext *cx, HandleObject wrapper,
                                HandleId id, bool *bp)
 {
     // Skip our Base if it isn't already ProxyHandler.
@@ -1858,34 +1879,27 @@ XrayWrapper<Base, Traits>::getPrototypeO
     // specializations (and therefore a helper class), which is all more trouble
     // than it's worth. Do a dynamic check.
     if (Base::hasSecurityPolicy())
         return Base::getPrototypeOf(cx, wrapper, protop);
 
     RootedObject target(cx, Traits::getTargetObject(wrapper));
     RootedObject expando(cx, Traits::singleton.getExpandoObject(cx, target, wrapper));
 
-    // We want to keep the Xray's prototype distinct from that of content, but only
-    // if there's been a set. If there's not an expando, or the expando slot is |undefined|,
-    // hand back content's proto, appropriately wrapped.
-    //
-    // NB: Our baseclass's getPrototypeOf() will appropriately wrap its return value, so there is
-    // no need for us to.
-
-    if (!expando)
-        return Base::getPrototypeOf(cx, wrapper, protop);
+    // We want to keep the Xray's prototype distinct from that of content, but
+    // only if there's been a set. If there's not an expando, or the expando
+    // slot is |undefined|, hand back the default proto, appropriately wrapped.
 
     RootedValue v(cx);
-    {
+    if (expando) {
         JSAutoCompartment ac(cx, expando);
         v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE);
     }
-
     if (v.isUndefined())
-        return Base::getPrototypeOf(cx, wrapper, protop);
+        return getPrototypeOfHelper(cx, wrapper, target, protop);
 
     protop.set(v.toObjectOrNull());
     return JS_WrapObject(cx, protop);
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::setPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -23,17 +23,17 @@ namespace xpc {
 bool
 holder_get(JSContext *cx, JS::HandleObject holder, JS::HandleId id, JS::MutableHandleValue vp);
 bool
 holder_set(JSContext *cx, JS::HandleObject holder, JS::HandleId id, bool strict,
            JS::MutableHandleValue vp);
 
 namespace XrayUtils {
 
-extern const JSClass HolderClass;
+bool IsXPCWNHolderClass(const JSClass *clasp);
 
 bool CloneExpandoChain(JSContext *cx, JSObject *src, JSObject *dst);
 
 bool
 IsTransparent(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id);
 
 JSObject *
 GetNativePropertiesObject(JSContext *cx, JSObject *wrapper);
@@ -109,16 +109,37 @@ class XrayWrapper : public Base {
     virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
                                 JS::MutableHandleObject protop) MOZ_OVERRIDE;
     virtual bool setPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
                                 JS::HandleObject proto, bool *bp) MOZ_OVERRIDE;
 
     static XrayWrapper singleton;
 
   private:
+    template <bool HasPrototype>
+    typename mozilla::EnableIf<HasPrototype, bool>::Type
+        getPrototypeOfHelper(JSContext *cx, JS::HandleObject wrapper,
+                             JS::HandleObject target, JS::MutableHandleObject protop)
+    {
+        return Traits::singleton.getPrototypeOf(cx, wrapper, target, protop);
+    }
+    template <bool HasPrototype>
+    typename mozilla::EnableIf<!HasPrototype, bool>::Type
+        getPrototypeOfHelper(JSContext *cx, JS::HandleObject wrapper,
+                             JS::HandleObject target, JS::MutableHandleObject protop)
+    {
+        return Base::getPrototypeOf(cx, wrapper, protop);
+    }
+    bool getPrototypeOfHelper(JSContext *cx, JS::HandleObject wrapper,
+                              JS::HandleObject target, JS::MutableHandleObject protop)
+    {
+        return getPrototypeOfHelper<Traits::HasPrototype>(cx, wrapper, target,
+                                                          protop);
+    }
+
     bool enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
                    JS::AutoIdVector &props);
 };
 
 #define PermissiveXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::XPCWrappedNativeXrayTraits>
 #define SecurityXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::XPCWrappedNativeXrayTraits>
 #define PermissiveXrayDOM xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::DOMXrayTraits>
 #define SecurityXrayDOM xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::DOMXrayTraits>
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -3481,17 +3481,23 @@ PresShell::ScrollFrameRectIntoView(nsIFr
   nsRect rect = aRect;
   nsIFrame* container = aFrame;
   // Walk up the frame hierarchy scrolling the rect into view and
   // keeping rect relative to container
   do {
     nsIScrollableFrame* sf = do_QueryFrame(container);
     if (sf) {
       nsPoint oldPosition = sf->GetScrollPosition();
-      ScrollToShowRect(container, sf, rect - sf->GetScrolledFrame()->GetPosition(),
+      nsRect targetRect = rect;
+      if (container->StyleDisplay()->mOverflowClipBox ==
+            NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX) {
+        nsMargin padding = container->GetUsedPadding();
+        targetRect.Inflate(padding);
+      }
+      ScrollToShowRect(container, sf, targetRect - sf->GetScrolledFrame()->GetPosition(),
                        aVertical, aHorizontal, aFlags);
       nsPoint newPosition = sf->GetScrollPosition();
       // If the scroll position increased, that means our content moved up,
       // so our rect's offset should decrease
       rect += oldPosition - newPosition;
 
       if (oldPosition != newPosition) {
         didScroll = true;
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-1-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcases for overflow-clip-box:content-box</title>
+    <style type="text/css">
+        html,body {
+            color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
+        }
+.block {
+  border:1px solid grey; height:50px; width:200px; padding:20px;
+  overflow:auto; overflow-clip-box:padding-box;
+}
+.rel { position:relative; }
+.mask1 { position:absolute; width:20px; background:white; top:0; bottom:0; right:0; }
+mask {
+  display:block;
+  position:absolute;
+  left: -1px;
+  bottom: -1px;
+  height: 25px;
+  width: 80%;
+  background:black;
+}
+    </style>
+</head>
+<body>
+
+<div style="position:relative;">
+<div contenteditable=true spellcheck=false tabindex=0 id=x class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<span style="padding-right:20px">X</span><div class=mask1></div></div>
+<mask></mask>
+</div>
+
+<script>
+var x = document.getElementById('x');
+x.focus();
+window.getSelection().collapse(x,0);
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-1.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcases for overflow-clip-box:content-box</title>
+    <style type="text/css">
+        html,body {
+            color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
+        }
+.block {
+  border:1px solid grey; height:50px; width:200px; padding:20px;
+  overflow:auto; overflow-clip-box:content-box;
+}
+mask {
+  display:block;
+  position:absolute;
+  left: -1px;
+  bottom: -1px;
+  height: 25px;
+  width: 80%;
+  background:black;
+}
+    </style>
+</head>
+<body>
+
+<div style="position:relative;">
+<div contenteditable=true spellcheck=false tabindex=0 id=x class="block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
+<mask></mask>
+</div>
+<script>
+var x = document.getElementById('x');
+x.focus();
+window.getSelection().collapse(x,0);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-2-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcases for overflow-clip-box:content-box</title>
+    <style type="text/css">
+        html,body {
+            color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
+        }
+.block {
+  border:1px solid grey; height:50px; width:200px; padding:20px;
+  overflow:auto; overflow-clip-box:padding-box;
+  line-height:1px;
+}
+.rel { position:relative; }
+.mask1 { position:absolute; width:20px;  background:white; top:0; bottom:0; right:0; }
+.mask2 { position:absolute; height:20px; background:white; top:0; left:40px; right:0; }
+mask {
+  display:block;
+  position:absolute;
+  left: -1px;
+  bottom: -1px;
+  height: 25px;
+  width: 80%;
+  background:black;
+}
+    </style>
+</head>
+<body>
+
+<div style="position:relative;">
+<div contenteditable=true spellcheck=false tabindex=0 id=x class="rel block">&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<span style="padding-right:20px">X</span><div class=mask2></div><div class=mask1></div></div>
+<mask></mask>
+</div>
+
+<script>
+var x = document.getElementById('x');
+x.focus();
+window.getSelection().collapse(x,0);
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-2.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcases for overflow-clip-box:content-box</title>
+    <style type="text/css">
+        html,body {
+            color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
+        }
+.block {
+  border:1px solid grey; height:50px; width:200px; padding:20px;
+  overflow:auto; overflow-clip-box:content-box;
+  line-height:1px;
+}
+.rel { position:relative; }
+mask {
+  display:block;
+  position:absolute;
+  left: -1px;
+  bottom: -1px;
+  height: 25px;
+  width: 80%;
+  background:black;
+}
+    </style>
+</head>
+<body>
+
+<div style="position:relative;">
+<div contenteditable=true spellcheck=false tabindex=0 id=x class="block">&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
+<mask></mask>
+</div>
+<script>
+var x = document.getElementById('x');
+x.focus();
+window.getSelection().collapse(x,0);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-3-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcases for overflow-clip-box:content-box</title>
+    <style type="text/css">
+        html,body {
+            color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
+        }
+    div {
+      width: 100px; padding-right:50px; overflow-clip-box:padding-box;
+      overflow:hidden;
+    }
+.rel { position:relative; }
+.mask5 { position:absolute; height:40px; background:white; top:3px; left:0px; width:50px; }
+    </style>
+</head>
+<body>
+
+<div contenteditable=true spellcheck=false tabindex=0 id=x class="block"><span style="padding-right:50px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span></div>
+
+<script>
+var x = document.getElementById('x');
+x.focus();
+x.scrollLeft=100000
+window.getSelection().collapse(x,1);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-3.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcases for overflow-clip-box:content-box</title>
+    <style type="text/css">
+        html,body {
+            color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
+        }
+    div {
+      width: 100px; padding-right:50px; overflow-clip-box:content-box;
+      overflow:hidden;
+    }
+    </style>
+</head>
+<body>
+
+<div contenteditable=true spellcheck=false tabindex=0 id=x class="block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
+
+<script>
+var x = document.getElementById('x');
+x.focus();
+x.scrollLeft=100000
+window.getSelection().collapse(x,1);
+</script>
+</body>
+</html>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -139,16 +139,22 @@ support-files =
   bug664087-1.html
   bug664087-1-ref.html
   bug664087-2.html
   bug664087-2-ref.html
   bug682712-1.html
   bug682712-1-ref.html
   bug746993-1.html
   bug746993-1-ref.html
+  bug966992-1.html
+  bug966992-1-ref.html
+  bug966992-2.html
+  bug966992-2-ref.html
+  bug966992-3.html
+  bug966992-3-ref.html
 [test_bug514127.html]
 [test_bug518777.html]
 [test_bug548545.xhtml]
 [test_bug558663.html]
 [test_bug559499.html]
 [test_bug569520.html]
 [test_bug582181-1.html]
 [test_bug582181-2.html]
--- a/layout/base/tests/test_reftests_with_caret.html
+++ b/layout/base/tests/test_reftests_with_caret.html
@@ -137,16 +137,21 @@ var tests = [
     function() {SpecialPowers.clearUserPref("bidi.browser.ui");} ,
     [ 'bug746993-1.html' , 'bug746993-1-ref.html' ] ,
 ];
 
 if (navigator.appVersion.indexOf("Android") == -1 &&
   SpecialPowers.Services.appinfo.name != "B2G") {
   tests.push([ 'bug512295-1.html' , 'bug512295-1-ref.html' ]);
   tests.push([ 'bug512295-2.html' , 'bug512295-2-ref.html' ]);
+  tests.push(function() {SpecialPowers.setBoolPref("layout.css.overflow-clip-box.enabled", true);});
+  tests.push([ 'bug966992-1.html' , 'bug966992-1-ref.html' ]);
+  tests.push([ 'bug966992-2.html' , 'bug966992-2-ref.html' ]);
+  tests.push([ 'bug966992-3.html' , 'bug966992-3-ref.html' ]);
+  tests.push(function() {SpecialPowers.setBoolPref("layout.css.overflow-clip-box.enabled", false);});
 } else {
   is(SpecialPowers.getIntPref("layout.spellcheckDefault"), 0, "Spellcheck should be turned off for this platrom or this if..else check removed");
 }
 
 var testIndex = 0;
 
 function nextTest() {
   if (testIndex < tests.length) {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1604,21 +1604,30 @@ ApplyOverflowClipping(nsDisplayListBuild
   // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
   // frames, and any non-visible value for blocks in a paginated context).
   // We allow -moz-hidden-unscrollable to apply to any kind of frame. This
   // is required by comboboxes which make their display text (an inline frame)
   // have clipping.
   if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) {
     return;
   }
-  nsRect rect = aFrame->GetPaddingRectRelativeToSelf() +
-      aBuilder->ToReferenceFrame(aFrame);
+  nsRect clipRect;
+  bool haveRadii = false;
   nscoord radii[8];
-  bool haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
-  aClipState.ClipContainingBlockDescendantsExtra(rect, haveRadii ? radii : nullptr);
+  if (aFrame->StyleDisplay()->mOverflowClipBox ==
+        NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
+    clipRect = aFrame->GetPaddingRectRelativeToSelf() +
+      aBuilder->ToReferenceFrame(aFrame);
+    haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
+  } else {
+    clipRect = aFrame->GetContentRectRelativeToSelf() +
+      aBuilder->ToReferenceFrame(aFrame);
+    // XXX border-radius
+  }
+  aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr);
 }
 
 #ifdef DEBUG
 static void PaintDebugBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
      const nsRect& aDirtyRect, nsPoint aPt) {
   nsRect r(aPt, aFrame->GetSize());
   if (aFrame->HasView()) {
     aCtx->SetColor(NS_RGB(0,0,255));
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3,16 +3,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/. */
 
 /* rendering object to wrap rendering objects that should be scrollable */
 
 #include "nsGfxScrollFrame.h"
 
 #include "base/compiler_specific.h"
+#include "DisplayItemClip.h"
 #include "nsCOMPtr.h"
 #include "nsPresContext.h"
 #include "nsView.h"
 #include "nsIScrollable.h"
 #include "nsContainerFrame.h"
 #include "nsGkAtoms.h"
 #include "nsINameSpaceManager.h"
 #include "nsContentList.h"
@@ -396,37 +397,38 @@ nsresult
 nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
                                        bool aAssumeHScroll,
                                        bool aAssumeVScroll,
                                        nsHTMLReflowMetrics* aMetrics,
                                        bool aFirstPass)
 {
   // these could be NS_UNCONSTRAINEDSIZE ... std::min arithmetic should
   // be OK
-  nscoord paddingLR = aState->mReflowState.ComputedPhysicalPadding().LeftRight();
-
-  nscoord availWidth = aState->mReflowState.ComputedWidth() + paddingLR;
+  const nsMargin& padding = aState->mReflowState.ComputedPhysicalPadding();
+  nscoord availWidth = aState->mReflowState.ComputedWidth() + padding.LeftRight();
 
   nscoord computedHeight = aState->mReflowState.ComputedHeight();
   nscoord computedMinHeight = aState->mReflowState.ComputedMinHeight();
   nscoord computedMaxHeight = aState->mReflowState.ComputedMaxHeight();
   if (!ShouldPropagateComputedHeightToScrolledContent()) {
     computedHeight = NS_UNCONSTRAINEDSIZE;
     computedMinHeight = 0;
     computedMaxHeight = NS_UNCONSTRAINEDSIZE;
   }
   if (aAssumeHScroll) {
     nsSize hScrollbarPrefSize;
     GetScrollbarMetrics(aState->mBoxState, mHelper.mHScrollbarBox,
                         nullptr, &hScrollbarPrefSize, false);
-    if (computedHeight != NS_UNCONSTRAINEDSIZE)
+    if (computedHeight != NS_UNCONSTRAINEDSIZE) {
       computedHeight = std::max(0, computedHeight - hScrollbarPrefSize.height);
+    }
     computedMinHeight = std::max(0, computedMinHeight - hScrollbarPrefSize.height);
-    if (computedMaxHeight != NS_UNCONSTRAINEDSIZE)
+    if (computedMaxHeight != NS_UNCONSTRAINEDSIZE) {
       computedMaxHeight = std::max(0, computedMaxHeight - hScrollbarPrefSize.height);
+    }
   }
 
   if (aAssumeVScroll) {
     nsSize vScrollbarPrefSize;
     GetScrollbarMetrics(aState->mBoxState, mHelper.mVScrollbarBox,
                         nullptr, &vScrollbarPrefSize, true);
     availWidth = std::max(0, availWidth - vScrollbarPrefSize.width);
   }
@@ -434,17 +436,17 @@ nsHTMLScrollFrame::ReflowScrolledFrame(S
   nsPresContext* presContext = PresContext();
 
   // Pass false for aInit so we can pass in the correct padding.
   nsHTMLReflowState kidReflowState(presContext, aState->mReflowState,
                                    mHelper.mScrolledFrame,
                                    nsSize(availWidth, NS_UNCONSTRAINEDSIZE),
                                    -1, -1, nsHTMLReflowState::CALLER_WILL_INIT);
   kidReflowState.Init(presContext, -1, -1, nullptr,
-                      &aState->mReflowState.ComputedPhysicalPadding());
+                      &padding);
   kidReflowState.mFlags.mAssumingHScrollbar = aAssumeHScroll;
   kidReflowState.mFlags.mAssumingVScrollbar = aAssumeVScroll;
   kidReflowState.SetComputedHeight(computedHeight);
   kidReflowState.ComputedMinHeight() = computedMinHeight;
   kidReflowState.ComputedMaxHeight() = computedMaxHeight;
 
   // Temporarily set mHasHorizontalScrollbar/mHasVerticalScrollbar to
   // reflect our assumptions while we reflow the child.
@@ -474,16 +476,28 @@ nsHTMLScrollFrame::ReflowScrolledFrame(S
   // setting their mOverflowArea. This is wrong because every frame should
   // always set mOverflowArea. In fact nsObjectFrame and nsFrameFrame don't
   // support the 'outline' property because of this. Rather than fix the world
   // right now, just fix up the overflow area if necessary. Note that we don't
   // check HasOverflowRect() because it could be set even though the
   // overflow area doesn't include the frame bounds.
   aMetrics->UnionOverflowAreasWithDesiredBounds();
 
+  if (MOZ_UNLIKELY(StyleDisplay()->mOverflowClipBox ==
+                     NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
+    nsOverflowAreas childOverflow;
+    nsLayoutUtils::UnionChildOverflow(mHelper.mScrolledFrame, childOverflow);
+    nsRect childScrollableOverflow = childOverflow.ScrollableOverflow();
+    childScrollableOverflow.Inflate(padding);
+    nsRect contentArea = nsRect(0, 0, availWidth, computedHeight);
+    if (!contentArea.Contains(childScrollableOverflow)) {
+      aMetrics->mOverflowAreas.ScrollableOverflow() = childScrollableOverflow;
+    }
+  }
+
   aState->mContentsOverflowAreas = aMetrics->mOverflowAreas;
   aState->mReflowedContentsWithHScrollbar = aAssumeHScroll;
   aState->mReflowedContentsWithVScrollbar = aAssumeVScroll;
 
   return rv;
 }
 
 bool
@@ -2267,20 +2281,84 @@ static bool IsFocused(nsIContent* aConte
   // walk up the tree until we reach a non-anonymous element.
   while (aContent && aContent->IsInAnonymousSubtree()) {
     aContent = aContent->GetParent();
   }
 
   return aContent ? nsContentUtils::IsFocusedContent(aContent) : false;
 }
 
+static bool
+ShouldBeClippedByFrame(nsIFrame* aClipFrame, nsIFrame* aClippedFrame)
+{
+  return nsLayoutUtils::IsProperAncestorFrame(aClipFrame, aClippedFrame);
+}
+
+static void
+ClipItemsExceptCaret(nsDisplayList* aList, nsDisplayListBuilder* aBuilder,
+                     nsIFrame* aClipFrame, const DisplayItemClip& aClip)
+{
+  nsDisplayItem* i = aList->GetBottom();
+  for (; i; i = i->GetAbove()) {
+    if (!::ShouldBeClippedByFrame(aClipFrame, i->Frame())) {
+      continue;
+    }
+
+    bool unused;
+    nsRect bounds = i->GetBounds(aBuilder, &unused);
+    bool isAffectedByClip = aClip.IsRectAffectedByClip(bounds);
+    if (isAffectedByClip && nsDisplayItem::TYPE_CARET == i->GetType()) {
+      // Don't clip the caret if it overflows vertically only, and by half
+      // its height at most.  This is to avoid clipping it when the line-height
+      // is small.
+      auto half = bounds.height / 2;
+      bounds.y += half;
+      bounds.height -= half;
+      isAffectedByClip = aClip.IsRectAffectedByClip(bounds);
+      if (isAffectedByClip) {
+        // Don't clip the caret if it's just outside on the right side.
+        nsRect rightSide(bounds.x - 1, bounds.y, 1, bounds.height);
+        isAffectedByClip = aClip.IsRectAffectedByClip(rightSide);
+        // Also, avoid clipping it in a zero-height line box (heuristic only).
+        if (isAffectedByClip) {
+          isAffectedByClip = i->Frame()->GetRect().height != 0;
+        }
+      }
+    }
+    if (isAffectedByClip) {
+      DisplayItemClip newClip;
+      newClip.IntersectWith(i->GetClip());
+      newClip.IntersectWith(aClip);
+      i->SetClip(aBuilder, newClip);
+    }
+    nsDisplayList* children = i->GetSameCoordinateSystemChildren();
+    if (children) {
+      ClipItemsExceptCaret(children, aBuilder, aClipFrame, aClip);
+    }
+  }
+}
+
+static void
+ClipListsExceptCaret(nsDisplayListCollection* aLists,
+                     nsDisplayListBuilder* aBuilder,
+                     nsIFrame* aClipFrame,
+                     const DisplayItemClip& aClip)
+{
+  ::ClipItemsExceptCaret(aLists->BorderBackground(), aBuilder, aClipFrame, aClip);
+  ::ClipItemsExceptCaret(aLists->BlockBorderBackgrounds(), aBuilder, aClipFrame, aClip);
+  ::ClipItemsExceptCaret(aLists->Floats(), aBuilder, aClipFrame, aClip);
+  ::ClipItemsExceptCaret(aLists->PositionedDescendants(), aBuilder, aClipFrame, aClip);
+  ::ClipItemsExceptCaret(aLists->Outlines(), aBuilder, aClipFrame, aClip);
+  ::ClipItemsExceptCaret(aLists->Content(), aBuilder, aClipFrame, aClip);
+}
+
 void
 ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
-                                        const nsRect&           aDirtyRect,
-                                        const nsDisplayListSet& aLists)
+                                    const nsRect&           aDirtyRect,
+                                    const nsDisplayListSet& aLists)
 {
   if (aBuilder->IsForImageVisibility()) {
     mLastUpdateImagesPos = GetScrollPosition();
   }
 
   mOuter->DisplayBorderBackgroundOutline(aBuilder, aLists);
 
   if (aBuilder->IsPaintingToWindow()) {
@@ -2325,23 +2403,22 @@ ScrollFrameHelper::BuildDisplayList(nsDi
   // in the positioned-elements layer on top of everything else by the call
   // to AppendScrollPartsTo(..., true) further down.
   AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
                       false);
 
   // Overflow clipping can never clip frames outside our subtree, so there
   // is no need to worry about whether we are a moving frame that might clip
   // non-moving frames.
-  nsRect dirtyRect;
   // Not all our descendants will be clipped by overflow clipping, but all
   // the ones that aren't clipped will be out of flow frames that have already
   // had dirty rects saved for them by their parent frames calling
   // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our
   // dirty rect here.
-  dirtyRect.IntersectRect(aDirtyRect, mScrollPort);
+  nsRect dirtyRect = aDirtyRect.Intersect(mScrollPort);
 
   // Override the dirty rectangle if the displayport has been set.
   nsRect displayPort;
   bool usingDisplayport =
     nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort) &&
     !aBuilder->IsForEventDelivery();
   if (usingDisplayport) {
     dirtyRect = displayPort;
@@ -2393,16 +2470,35 @@ ScrollFrameHelper::BuildDisplayList(nsDi
       } else {
         clipState.ClipContainingBlockDescendants(clip, haveRadii ? radii : nullptr);
       }
     }
 
     mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, scrolledContent);
   }
 
+  if (MOZ_UNLIKELY(mOuter->StyleDisplay()->mOverflowClipBox ==
+                     NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
+    // We only clip if there is *scrollable* overflow, to avoid clipping
+    // *visual* overflow unnecessarily.
+    nsRect clipRect = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
+    nsRect so = mScrolledFrame->GetScrollableOverflowRect();
+    if (clipRect.width != so.width || clipRect.height != so.height ||
+        so.x < 0 || so.y < 0) {
+      // The 'scrolledContent' items are clipped to the padding-box at this point.
+      // Now clip them again to the content-box, except the nsDisplayCaret item
+      // which we allow to overflow the content-box in various situations --
+      // see ::ClipItemsExceptCaret.
+      clipRect.Deflate(mOuter->GetUsedPadding());
+      DisplayItemClip clip;
+      clip.SetTo(clipRect);
+      ::ClipListsExceptCaret(&scrolledContent, aBuilder, mScrolledFrame, clip);
+    }
+  }
+
   // Since making new layers is expensive, only use nsDisplayScrollLayer
   // if the area is scrollable and we're the content process (unless we're on
   // B2G, where we support async scrolling for scrollable elements in the
   // parent process as well).
   // When a displayport is being used, force building of a layer so that
   // CompositorParent can always find the scrollable layer for the root content
   // document.
   // If the element is marked 'scrollgrab', also force building of a layer
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/966992-1-ref.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait"><head>
+    <meta charset="utf-8">
+    <title>Testcases for overflow-clip-box:content-box</title>
+    <style type="text/css">
+font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+
+        html,body {
+            color:black; background-color:white; font:16px DejaVuSansMono!important; padding:0; margin:7px;
+        }
+
+    input {
+      width: 100px; padding:50px; -moz-appearance:none; overflow-clip-box:padding-box;
+      border: 3px solid black;
+    }
+    textarea, #textarea {
+      width: 160px; height:110px; padding:40px; overflow:scroll; -moz-appearance:none; overflow-clip-box:padding-box;
+      border: 3px solid black;
+    }
+    #textarea { word-break: break-all; font:14px DejaVuSansMono!important; }
+
+
+p {
+ position:absolute;
+ margin:0;
+ width:70%;
+ height: 1px;
+ background:magenta;
+}
+.rel p { width:200%; }
+.block {
+  border:1px solid grey; height:50px; width:200px; padding:20px;
+  overflow:auto; overflow-clip-box:padding-box;
+}
+.rel { position:relative; }
+.mask1 { position:absolute; width:20px; background:white; top:0; bottom:0; right:0; }
+.mask2 { position:absolute; width:20px; background:white; top:0px; bottom:-15px; right:220px; z-index:99; }
+.mask3 { position:absolute; width:20px; background:white; top:0; bottom:0; left:200px; }
+.mask4 { position:absolute; height:40px; background:white; top:4px; left:3px; width:210px; z-index:99; }
+.mask5 { position:absolute; height:40px; background:white; top:3px; right:3px; width:50px; }
+    </style>
+<script>
+function runTest() {
+  // the timeout is for avoiding differences in scrollbar fading
+  document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+<body onload="setTimeout(runTest,5000)">
+
+<div class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p style="padding-right:20px"></p><div class=mask1></div></div>
+<div style="float:right">
+
+<div class="rel block" style="box-sizing:border-box;height:90px"><span style="padding-right:20px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span><div class=mask1></div></div>
+
+</div>
+
+<div class="rel block"><span style="padding-right:20px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span><p></p><div class=mask1></div></div>
+<div id="d1" class="rel block"><span style="padding-right:20px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span><span style="position:relative;"><div class=mask2></div><div class=mask1></div></span><p></p></div>
+<script>
+document.getElementById("d1").scrollLeft = "100000";
+</script>
+<div class="block"><span style="padding-right:20px"><span style="position:relative;"><div class=mask3></div>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span></span><p></p></div>
+
+<span style="position:relative"><input spellcheck=false type="text" placeholder="someveryveryveryveryverylongvalue"><div class=mask5></div></span>
+<span style="position:relative"><input spellcheck=false type="text" value="someveryveryveryveryverylongvalue"><div class=mask5></div></span><br>
+<span style="position:relative"><input spellcheck=false type="password" value="someveryveryveryveryverylongpassword"><div class=mask5></div></span>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/966992-1.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait"><head>
+    <meta charset="utf-8">
+    <title>Testcases for overflow-clip-box:content-box</title>
+    <style type="text/css">
+font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+
+        html,body {
+            color:black; background-color:white; font:16px DejaVuSansMono!important; padding:0; margin:7px;
+        }
+
+    input {
+      width: 100px; padding:50px; -moz-appearance:none; overflow-clip-box:content-box;
+      border: 3px solid black;
+    }
+    textarea {
+      width: 160px; height:110px; padding:40px; overflow:scroll; -moz-appearance:none; overflow-clip-box:content-box;
+      border: 3px solid black;font:14px DejaVuSansMono!important;
+    }
+
+p {
+ position:absolute;
+ margin:0;
+ width:70%;
+ height: 1px;
+ background:magenta;
+}
+.rel p { width:200%; }
+.block {
+  border:1px solid grey; height:50px; width:200px; padding:20px;
+  overflow:auto; overflow-clip-box:content-box;
+}
+.rel { position:relative; }
+    </style>
+<script>
+function runTest() {
+  // the timeout is for avoiding differences in scrollbar fading
+  document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+<body onload="setTimeout(runTest,5000)">
+
+<div class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p></p></div>
+<div style="float:right">
+
+<div class="block" style="-moz-box-sizing:border-box;height:90px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
+</div>
+
+<div class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p></p></div>
+<div id="d1" class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p></p></div>
+<script>
+document.getElementById("d1").scrollLeft = "100000";
+</script>
+<div class="block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p></p></div>
+
+<input spellcheck=false type="text" placeholder="someveryveryveryveryverylongvalue">
+<input spellcheck=false type="text" value="someveryveryveryveryverylongvalue"><br>
+<input spellcheck=false type="password" value="someveryveryveryveryverylongpassword">
+
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -234,17 +234,17 @@ skip-if(B2G) fails-if(Android) != 192767
 == 234686-19.html 234686-ref.html
 skip-if(B2G) == 234964-1.html 234964-1-ref.html
 == 234964-2.html 234964-2-ref.html
 == 235593-1.html 235593-1-ref.html
 == 236539-1.html 236539-1-ref.html
 == 240029-1.html 240029-1-ref.html
 == 240470-1.html 240470-1-ref.html
 skip-if(B2G) == 240933-1.html 240933-1-ref.html
-skip-if(B2G) == 240933-2.html 240933-2-ref.html
+skip-if(Android||B2G) == 240933-2.html 240933-2-ref.html
 == 243266-1.html 243266-1-ref.html
 == 243302-1.html 243302-1-ref.html
 skip-if(B2G) == 243519-1.html 243519-1-ref.html
 == 243519-2.html 243519-2-ref.html
 == 243519-3.html 243519-3-ref.html
 == 243519-4a.html 243519-4-ref.html
 == 243519-4b.html 243519-4-ref.html
 == 243519-4c.html 243519-4-ref.html
@@ -1791,10 +1791,11 @@ fuzzy-if(OSX==10.6,2,30) == 933264-1.htm
 == 941940-1.html 941940-1-ref.html
 == 942017.html 942017-ref.html
 == 942672-1.html 942672-1-ref.html
 == 953334-win32-clipping.html 953334-win32-clipping-ref.html
 == 956513-1.svg 956513-1-ref.svg
 == 944291-1.html 944291-1-ref.html
 == 957770-1.svg 957770-1-ref.svg
 == 960277-1.html 960277-1-ref.html
+pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,10) == 966992-1.html 966992-1-ref.html
 skip-if(Android) == 966510-1.html 966510-1-ref.html # scrollable elements other than the root probably won't work well on android until bug 776030 is fixed
 skip-if(Android) == 966510-2.html 966510-2-ref.html # same as above
--- a/layout/reftests/forms/placeholder/reftest.list
+++ b/layout/reftests/forms/placeholder/reftest.list
@@ -11,17 +11,17 @@
 == placeholder-1-text.html placeholder-visible-ref.html
 == placeholder-1-password.html placeholder-visible-ref.html
 == placeholder-1-textarea.html placeholder-visible-textarea-ref.html
 == placeholder-2.html placeholder-visible-ref.html
 == placeholder-2-textarea.html placeholder-visible-textarea-ref.html
 == placeholder-3.html placeholder-overridden-ref.html
 == placeholder-4.html placeholder-overridden-ref.html
 == placeholder-5.html placeholder-visible-ref.html
-== placeholder-6.html placeholder-overflow-ref.html
+fuzzy-if(winWidget,160,6) == placeholder-6.html placeholder-overflow-ref.html
 skip-if(B2G) == placeholder-6-textarea.html placeholder-overflow-textarea-ref.html
 # needs-focus == placeholder-7.html placeholder-focus-ref.html
 # needs-focus == placeholder-8.html placeholder-focus-ref.html
 # needs-focus == placeholder-9.html placeholder-focus-ref.html
 needs-focus == placeholder-10.html placeholder-visible-ref.html
 == placeholder-11.html placeholder-visible-ref.html
 == placeholder-12.html placeholder-visible-ref.html
 == placeholder-13.html placeholder-visible-ref.html
--- a/layout/reftests/forms/textarea/padding-scrollbar-placement-ref.html
+++ b/layout/reftests/forms/textarea/padding-scrollbar-placement-ref.html
@@ -23,21 +23,29 @@
             #cover {
                 position: absolute;
                 left: 400px;
                 top: 50px;
                 width: 100px;
                 height: 300px;
                 background: black;
             }
+            #cover2 { /* corresponds to the bottom padding inside the textarea */
+                position: absolute;
+                left: 0px;
+                bottom: 0px;
+                width: 100%;
+                height: 50px;
+                background: white;
+            }
         </style>
     </head>
     <body>
         <script>
         var ss = [];
         for (var i = 0; i < 1000; ++i) {
           ss.push(i);
         }
-        document.write("<div id='t'>" + ss.join(" ") + "</div>");
+        document.write("<div id='t'><div id=cover2></div>" + ss.join(" ") + "</div>");
         </script>
         <div id="cover"></div>
     </body>
 </html>
--- a/layout/reftests/svg/text/multiple-x-percentages-3.html
+++ b/layout/reftests/svg/text/multiple-x-percentages-3.html
@@ -17,10 +17,9 @@ function doTest() {
   var text = iframe.contentDocument.querySelectorAll("text");
   text[0].firstChild.nodeValue += "!";
   text[1].firstChild.nodeValue += "!";
 
   document.documentElement.removeAttribute("class");
 }
 
 window.addEventListener("MozReftestInvalidate", doTest, false);
-setTimeout(doTest, 4000); // fallback for running outside reftest
 </script>
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -110,16 +110,17 @@ textarea {
   cursor: text;
   resize: both;
   -moz-binding: url("chrome://global/content/platformHTMLBindings.xml#textAreas");
   -moz-appearance: textfield-multiline;
   text-indent: 0;
   -moz-user-select: text;
   text-shadow: none;
   word-wrap: break-word;
+  overflow-clip-box: content-box;
 }
 
 textarea > scrollbar {
   cursor: default;
 }
 
 textarea > .anonymous-div,
 input > .anonymous-div,
@@ -132,16 +133,17 @@ textarea::-moz-placeholder {
   margin: 0px;
   text-decoration: inherit;
   -moz-text-decoration-color: inherit;
   -moz-text-decoration-style: inherit;
   display: inline-block;
   ime-mode: inherit;
   resize: inherit;
   -moz-control-character-visibility: visible;
+  overflow-clip-box: inherit;
 }
 
 textarea > .anonymous-div.wrap,
 input > .anonymous-div.wrap {
   white-space: pre-wrap;
 }
 textarea > .anonymous-div.inherit-overflow,
 input > .anonymous-div.inherit-overflow {
@@ -373,16 +375,21 @@ textarea:disabled {
   cursor: default;
 }
 
 option:disabled,
 optgroup:disabled {
   background-color: transparent;
 }
 
+input[type="text"],
+input[type="password"] {
+  overflow-clip-box: content-box;
+}
+
 /* hidden inputs */
 input[type="hidden"] {
   -moz-appearance: none;
   display: none !important;
   padding: 0;
   border: 0;
   cursor: auto;
   -moz-user-focus: ignore;
@@ -894,16 +901,17 @@ input[type=range]::-moz-range-thumb {
   -moz-user-select: none ! important;
 }
 
 input[type="number"] {
   -moz-appearance: number-input;
   /* Has to revert some properties applied by the generic input rule. */
   -moz-binding: none;
   width: 149px; /* to match type=text */
+  overflow-clip-box: content-box;
 }
 
 input[type=number]::-moz-number-wrapper {
   /* Prevent styling that would change the type of frame we construct. */
   display: flex;
   float: none !important;
   position: static !important;
   height: 100%;
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -242,16 +242,22 @@ public:
                                            nsRuleData* aRuleData,
                                            nsIURI* aDocURL,
                                            nsIURI* aBaseURL,
                                            nsIPrincipal* aDocPrincipal,
                                            nsCSSStyleSheet* aSheet,
                                            uint32_t aLineNumber,
                                            uint32_t aLineOffset);
 
+  nsCSSProperty LookupEnabledProperty(const nsAString& aProperty) {
+    return nsCSSProps::LookupProperty(aProperty, mUnsafeRulesEnabled ?
+                                                   nsCSSProps::eEnabledInUASheets :
+                                                   nsCSSProps::eEnabled);
+  }
+
 protected:
   class nsAutoParseCompoundProperty;
   friend class nsAutoParseCompoundProperty;
 
   class nsAutoFailingSupportsRule;
   friend class nsAutoFailingSupportsRule;
 
   class nsAutoSuppressErrors;
@@ -1300,17 +1306,21 @@ CSSParserImpl::ParseProperty(const nsCSS
   css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI);
   InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal);
   mSection = eCSSSection_General;
   scanner.SetSVGMode(aIsSVGMode);
 
   *aChanged = false;
 
   // Check for unknown or preffed off properties
-  if (eCSSProperty_UNKNOWN == aPropID || !nsCSSProps::IsEnabled(aPropID)) {
+  if (eCSSProperty_UNKNOWN == aPropID ||
+      !(nsCSSProps::IsEnabled(aPropID) ||
+        (mUnsafeRulesEnabled &&
+         nsCSSProps::PropHasFlags(aPropID,
+                                  CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS)))) {
     NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue(aPropID));
     REPORT_UNEXPECTED_P(PEUnknownProperty, propName);
     REPORT_UNEXPECTED(PEDeclDropped);
     OUTPUT_ERROR();
     ReleaseScanner();
     return NS_OK;
   }
 
@@ -1555,18 +1565,17 @@ CSSParserImpl::ParseKeyframeSelectorStri
 
 bool
 CSSParserImpl::EvaluateSupportsDeclaration(const nsAString& aProperty,
                                            const nsAString& aValue,
                                            nsIURI* aDocURL,
                                            nsIURI* aBaseURL,
                                            nsIPrincipal* aDocPrincipal)
 {
-  nsCSSProperty propID = nsCSSProps::LookupProperty(aProperty,
-                                                    nsCSSProps::eEnabled);
+  nsCSSProperty propID = LookupEnabledProperty(aProperty);
   if (propID == eCSSProperty_UNKNOWN) {
     return false;
   }
 
   nsCSSScanner scanner(aValue, 0);
   css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURL);
   InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal);
   nsAutoSuppressErrors suppressErrors(this);
@@ -3696,18 +3705,17 @@ CSSParserImpl::ParseSupportsConditionInP
 
   if (mToken.mType == eCSSToken_Ident) {
     if (!mToken.mIdent.LowerCaseEqualsLiteral("not")) {
       nsAutoString propertyName = mToken.mIdent;
       if (!ExpectSymbol(':', true)) {
         return false;
       }
 
-      nsCSSProperty propID = nsCSSProps::LookupProperty(propertyName,
-                                                        nsCSSProps::eEnabled);
+      nsCSSProperty propID = LookupEnabledProperty(propertyName);
       if (propID == eCSSProperty_UNKNOWN) {
         if (ExpectSymbol(')', true)) {
           UngetToken();
           return false;
         }
         aConditionMet = false;
         SkipUntil(')');
         UngetToken();
@@ -5738,17 +5746,17 @@ CSSParserImpl::ParseDeclaration(css::Dec
     if (!ParseVariableDeclaration(&variableType, variableValue)) {
       REPORT_UNEXPECTED_P(PEValueParsingError, propertyName);
       REPORT_UNEXPECTED(PEDeclDropped);
       OUTPUT_ERROR();
       return false;
     }
   } else {
     // Map property name to its ID.
-    propID = nsCSSProps::LookupProperty(propertyName, nsCSSProps::eEnabled);
+    propID = LookupEnabledProperty(propertyName);
     if (eCSSProperty_UNKNOWN == propID ||
         (aContext == eCSSContext_Page &&
          !nsCSSProps::PropHasFlags(propID,
                                    CSS_PROPERTY_APPLIES_TO_PAGE_RULE))) { // unknown property
       if (!NonMozillaVendorIdentifier(propertyName)) {
         REPORT_UNEXPECTED_P(PEUnknownProperty, propertyName);
         REPORT_UNEXPECTED(PEDeclDropped);
         OUTPUT_ERROR();
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2476,16 +2476,28 @@ CSS_PROP_OUTLINE(
     eStyleAnimType_nscoord)
 CSS_PROP_SHORTHAND(
     overflow,
     overflow,
     Overflow,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
 CSS_PROP_DISPLAY(
+    overflow-clip-box,
+    overflow_clip_box,
+    OverflowClipBox,
+    CSS_PROPERTY_PARSE_VALUE |
+        CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
+        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
+    "layout.css.overflow-clip-box.enabled",
+    VARIANT_HK,
+    kOverflowClipBoxKTable,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_DISPLAY(
     overflow-x,
     overflow_x,
     OverflowX,
     CSS_PROPERTY_PARSE_VALUE |
         // This is required by the UA stylesheet and can't be overridden.
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
     "",
     VARIANT_HK,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -382,65 +382,69 @@ nsCSSProps::LookupProperty(const nsACStr
   NS_ABORT_IF_FALSE(gPropertyTable, "no lookup table, needs addref");
 
   if (nsLayoutUtils::CSSVariablesEnabled() &&
       IsCustomPropertyName(aProperty)) {
     return eCSSPropertyExtra_variable;
   }
 
   nsCSSProperty res = nsCSSProperty(gPropertyTable->Lookup(aProperty));
-  // Check eCSSAliasCount against 0 to make it easy for the
-  // compiler to optimize away the 0-aliases case.
-  if (eCSSAliasCount != 0 && res >= eCSSProperty_COUNT) {
-    static_assert(eCSSProperty_UNKNOWN < eCSSProperty_COUNT,
-                  "assuming eCSSProperty_UNKNOWN doesn't hit this code");
-    if (IsEnabled(res) || aEnabled == eAny) {
-      res = gAliases[res - eCSSProperty_COUNT];
-      NS_ABORT_IF_FALSE(0 <= res && res < eCSSProperty_COUNT,
-                        "aliases must not point to other aliases");
-    } else {
+  if (MOZ_LIKELY(res < eCSSProperty_COUNT)) {
+    if (res != eCSSProperty_UNKNOWN && !IsEnabled(res, aEnabled)) {
       res = eCSSProperty_UNKNOWN;
     }
+    return res;
   }
-  if (res != eCSSProperty_UNKNOWN && aEnabled == eEnabled && !IsEnabled(res)) {
-    res = eCSSProperty_UNKNOWN;
+  MOZ_ASSERT(eCSSAliasCount != 0,
+             "'res' must be an alias at this point so we better have some!");
+  // We intentionally don't support eEnabledInUASheets for aliases yet
+  // because it's unlikely there will be a need for it.
+  if (IsEnabled(res) || aEnabled == eAny) {
+    res = gAliases[res - eCSSProperty_COUNT];
+    NS_ABORT_IF_FALSE(0 <= res && res < eCSSProperty_COUNT,
+                      "aliases must not point to other aliases");
+    if (IsEnabled(res) || aEnabled == eAny) {
+      return res;
+    }
   }
-  return res;
+  return eCSSProperty_UNKNOWN;
 }
 
 nsCSSProperty
 nsCSSProps::LookupProperty(const nsAString& aProperty, EnabledState aEnabled)
 {
   if (nsLayoutUtils::CSSVariablesEnabled() &&
       IsCustomPropertyName(aProperty)) {
     return eCSSPropertyExtra_variable;
   }
 
   // This is faster than converting and calling
   // LookupProperty(nsACString&).  The table will do its own
   // converting and avoid a PromiseFlatCString() call.
   NS_ABORT_IF_FALSE(gPropertyTable, "no lookup table, needs addref");
   nsCSSProperty res = nsCSSProperty(gPropertyTable->Lookup(aProperty));
-  // Check eCSSAliasCount against 0 to make it easy for the
-  // compiler to optimize away the 0-aliases case.
-  if (eCSSAliasCount != 0 && res >= eCSSProperty_COUNT) {
-    static_assert(eCSSProperty_UNKNOWN < eCSSProperty_COUNT,
-                  "assuming eCSSProperty_UNKNOWN doesn't hit this code");
-    if (IsEnabled(res) || aEnabled == eAny) {
-      res = gAliases[res - eCSSProperty_COUNT];
-      NS_ABORT_IF_FALSE(0 <= res && res < eCSSProperty_COUNT,
-                        "aliases must not point to other aliases");
-    } else {
+  if (MOZ_LIKELY(res < eCSSProperty_COUNT)) {
+    if (res != eCSSProperty_UNKNOWN && !IsEnabled(res, aEnabled)) {
       res = eCSSProperty_UNKNOWN;
     }
+    return res;
   }
-  if (res != eCSSProperty_UNKNOWN && aEnabled == eEnabled && !IsEnabled(res)) {
-    res = eCSSProperty_UNKNOWN;
+  MOZ_ASSERT(eCSSAliasCount != 0,
+             "'res' must be an alias at this point so we better have some!");
+  // We intentionally don't support eEnabledInUASheets for aliases yet
+  // because it's unlikely there will be a need for it.
+  if (IsEnabled(res) || aEnabled == eAny) {
+    res = gAliases[res - eCSSProperty_COUNT];
+    NS_ABORT_IF_FALSE(0 <= res && res < eCSSProperty_COUNT,
+                      "aliases must not point to other aliases");
+    if (IsEnabled(res) || aEnabled == eAny) {
+      return res;
+    }
   }
-  return res;
+  return eCSSProperty_UNKNOWN;
 }
 
 nsCSSFontDesc
 nsCSSProps::LookupFontDesc(const nsACString& aFontDesc)
 {
   NS_ABORT_IF_FALSE(gFontDescTable, "no lookup table, needs addref");
   return nsCSSFontDesc(gFontDescTable->Lookup(aFontDesc));
 }
@@ -1417,16 +1421,22 @@ const KTableValue nsCSSProps::kOverflowK
   // Deprecated:
   eCSSKeyword__moz_scrollbars_none, NS_STYLE_OVERFLOW_HIDDEN,
   eCSSKeyword__moz_scrollbars_horizontal, NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL,
   eCSSKeyword__moz_scrollbars_vertical, NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL,
   eCSSKeyword__moz_hidden_unscrollable, NS_STYLE_OVERFLOW_CLIP,
   eCSSKeyword_UNKNOWN,-1
 };
 
+const KTableValue nsCSSProps::kOverflowClipBoxKTable[] = {
+  eCSSKeyword_padding_box, NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX,
+  eCSSKeyword_content_box, NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX,
+  eCSSKeyword_UNKNOWN,-1
+};
+
 const KTableValue nsCSSProps::kOverflowSubKTable[] = {
   eCSSKeyword_auto, NS_STYLE_OVERFLOW_AUTO,
   eCSSKeyword_visible, NS_STYLE_OVERFLOW_VISIBLE,
   eCSSKeyword_hidden, NS_STYLE_OVERFLOW_HIDDEN,
   eCSSKeyword_scroll, NS_STYLE_OVERFLOW_SCROLL,
   // Deprecated:
   eCSSKeyword__moz_hidden_unscrollable, NS_STYLE_OVERFLOW_CLIP,
   eCSSKeyword_UNKNOWN,-1
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -189,16 +189,23 @@ static_assert((CSS_PROPERTY_PARSE_PROPER
 
 // This property's getComputedStyle implementation requires layout to be
 // flushed.
 #define CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH     (1<<20)
 
 // This property requires a stacking context.
 #define CSS_PROPERTY_CREATES_STACKING_CONTEXT     (1<<21)
 
+// This property is always enabled in UA sheets.  This is meant to be used
+// together with a pref that enables the property for non-UA sheets.
+// Note that if such a property has an alias, then any use of that alias
+// in an UA sheet will still be ignored unless the pref is enabled.
+// In other words, this bit has no effect on the use of aliases.
+#define CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS  (1<<22)
+
 /**
  * Types of animatable values.
  */
 enum nsStyleAnimType {
   // requires a custom implementation in
   // nsStyleAnimation::ExtractComputedValue
   eStyleAnimType_Custom,
 
@@ -249,16 +256,17 @@ public:
   typedef int16_t KTableValue;
 
   static void AddRefTable(void);
   static void ReleaseTable(void);
 
   // Given a property string, return the enum value
   enum EnabledState {
     eEnabled,
+    eEnabledInUASheets,
     eAny
   };
   // Looks up the property with name aProperty and returns its corresponding
   // nsCSSProperty value.  If aProperty is the name of a custom property,
   // then eCSSPropertyExtra_variable will be returned.
   static nsCSSProperty LookupProperty(const nsAString& aProperty,
                                       EnabledState aEnabled);
   static nsCSSProperty LookupProperty(const nsACString& aProperty,
@@ -434,16 +442,23 @@ public:
 
   static bool IsEnabled(nsCSSProperty aProperty) {
     NS_ABORT_IF_FALSE(0 <= aProperty &&
                       aProperty < eCSSProperty_COUNT_with_aliases,
                       "out of range");
     return gPropertyEnabled[aProperty];
   }
 
+  static bool IsEnabled(nsCSSProperty aProperty, EnabledState aEnabled) {
+    return IsEnabled(aProperty) ||
+      (aEnabled == eEnabledInUASheets &&
+       PropHasFlags(aProperty, CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS)) ||
+      aEnabled == eAny;
+  }
+
 public:
 
 #define CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(iter_, prop_)                    \
   for (const nsCSSProperty* iter_ = nsCSSProps::SubpropertyEntryFor(prop_);   \
        *iter_ != eCSSProperty_UNKNOWN; ++iter_) \
     if (nsCSSProps::IsEnabled(*iter_))
 
   // Keyword/Enum value tables
@@ -535,16 +550,17 @@ public:
   static const KTableValue kMathDisplayKTable[];
   static const KTableValue kContextOpacityKTable[];
   static const KTableValue kContextPatternKTable[];
   static const KTableValue kOrientKTable[];
   static const KTableValue kOutlineStyleKTable[];
   static const KTableValue kOutlineColorKTable[];
   static const KTableValue kOverflowKTable[];
   static const KTableValue kOverflowSubKTable[];
+  static const KTableValue kOverflowClipBoxKTable[];
   static const KTableValue kPageBreakKTable[];
   static const KTableValue kPageBreakInsideKTable[];
   static const KTableValue kPageMarksKTable[];
   static const KTableValue kPageSizeKTable[];
   static const KTableValue kPitchKTable[];
   static const KTableValue kPointerEventsKTable[];
   // Not const because we modify its entries when the pref
   // "layout.css.sticky.enabled" changes:
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3748,16 +3748,26 @@ nsComputedDOMStyle::DoGetOverflowY()
   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY,
                                    nsCSSProps::kOverflowSubKTable));
   return val;
 }
 
 CSSValue*
+nsComputedDOMStyle::DoGetOverflowClipBox()
+{
+  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  val->SetIdent(
+    nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
+                                   nsCSSProps::kOverflowClipBoxKTable));
+  return val;
+}
+
+CSSValue*
 nsComputedDOMStyle::DoGetResize()
 {
   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mResize,
                                                nsCSSProps::kResizeKTable));
   return val;
 }
 
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -393,16 +393,17 @@ private:
   mozilla::dom::CSSValue* DoGetDisplay();
   mozilla::dom::CSSValue* DoGetPosition();
   mozilla::dom::CSSValue* DoGetClip();
   mozilla::dom::CSSValue* DoGetImageOrientation();
   mozilla::dom::CSSValue* DoGetWillChange();
   mozilla::dom::CSSValue* DoGetOverflow();
   mozilla::dom::CSSValue* DoGetOverflowX();
   mozilla::dom::CSSValue* DoGetOverflowY();
+  mozilla::dom::CSSValue* DoGetOverflowClipBox();
   mozilla::dom::CSSValue* DoGetResize();
   mozilla::dom::CSSValue* DoGetPageBreakAfter();
   mozilla::dom::CSSValue* DoGetPageBreakBefore();
   mozilla::dom::CSSValue* DoGetPageBreakInside();
   mozilla::dom::CSSValue* DoGetTouchAction();
   mozilla::dom::CSSValue* DoGetTransform();
   mozilla::dom::CSSValue* DoGetTransformOrigin();
   mozilla::dom::CSSValue* DoGetPerspective();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -157,16 +157,17 @@ COMPUTED_STYLE_PROP(opacity,            
 // COMPUTED_STYLE_PROP(orphans,                    Orphans)
 //// COMPUTED_STYLE_PROP(outline,                  Outline)
 COMPUTED_STYLE_PROP(order,                         Order)
 COMPUTED_STYLE_PROP(outline_color,                 OutlineColor)
 COMPUTED_STYLE_PROP(outline_offset,                OutlineOffset)
 COMPUTED_STYLE_PROP(outline_style,                 OutlineStyle)
 COMPUTED_STYLE_PROP(outline_width,                 OutlineWidth)
 COMPUTED_STYLE_PROP(overflow,                      Overflow)
+COMPUTED_STYLE_PROP(overflow_clip_box,             OverflowClipBox)
 COMPUTED_STYLE_PROP(overflow_x,                    OverflowX)
 COMPUTED_STYLE_PROP(overflow_y,                    OverflowY)
 //// COMPUTED_STYLE_PROP(padding,                  Padding)
 COMPUTED_STYLE_PROP(padding_bottom,                PaddingBottom)
 COMPUTED_STYLE_PROP(padding_left,                  PaddingLeft)
 COMPUTED_STYLE_PROP(padding_right,                 PaddingRight)
 COMPUTED_STYLE_PROP(padding_top,                   PaddingTop)
 // COMPUTED_STYLE_PROP(page,                       Page)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5299,16 +5299,22 @@ nsRuleNode::ComputeDisplayData(void* aSt
     // If 'visible' is specified but doesn't match the other dimension, it
     // turns into 'auto'.
     if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
       display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
     if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
       display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
   }
 
+  SetDiscrete(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
+              canStoreInRuleTree,
+              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
+              parentDisplay->mOverflowClipBox,
+              NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX, 0, 0, 0, 0);
+
   SetDiscrete(*aRuleData->ValueForResize(), display->mResize, canStoreInRuleTree,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mResize,
               NS_STYLE_RESIZE_NONE, 0, 0, 0, 0);
 
   // clip property: length, auto, inherit
   const nsCSSValue* clipValue = aRuleData->ValueForClip();
   switch (clipValue->GetUnit()) {
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -565,24 +565,24 @@ static inline mozilla::css::Side operato
 #define NS_MATHML_DISPLAYSTYLE_BLOCK            1
 
 // See nsStylePosition::mWidth, mMinWidth, mMaxWidth
 #define NS_STYLE_WIDTH_MAX_CONTENT              0
 #define NS_STYLE_WIDTH_MIN_CONTENT              1
 #define NS_STYLE_WIDTH_FIT_CONTENT              2
 #define NS_STYLE_WIDTH_AVAILABLE                3
 
-// See nsStylePosition.mPosition
+// See nsStyleDisplay.mPosition
 #define NS_STYLE_POSITION_STATIC                0
 #define NS_STYLE_POSITION_RELATIVE              1
 #define NS_STYLE_POSITION_ABSOLUTE              2
 #define NS_STYLE_POSITION_FIXED                 3
 #define NS_STYLE_POSITION_STICKY                4
 
-// See nsStylePosition.mClip
+// See nsStyleDisplay.mClip
 #define NS_STYLE_CLIP_AUTO                      0x00
 #define NS_STYLE_CLIP_RECT                      0x01
 #define NS_STYLE_CLIP_TYPE_MASK                 0x0F
 #define NS_STYLE_CLIP_LEFT_AUTO                 0x10
 #define NS_STYLE_CLIP_TOP_AUTO                  0x20
 #define NS_STYLE_CLIP_RIGHT_AUTO                0x40
 #define NS_STYLE_CLIP_BOTTOM_AUTO               0x80
 
@@ -593,25 +593,29 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_FRAME_0                        2
 #define NS_STYLE_FRAME_1                        3
 #define NS_STYLE_FRAME_ON                       4
 #define NS_STYLE_FRAME_OFF                      5
 #define NS_STYLE_FRAME_AUTO                     6
 #define NS_STYLE_FRAME_SCROLL                   7
 #define NS_STYLE_FRAME_NOSCROLL                 8
 
-// See nsStylePosition.mOverflow
+// See nsStyleDisplay.mOverflow
 #define NS_STYLE_OVERFLOW_VISIBLE               0
 #define NS_STYLE_OVERFLOW_HIDDEN                1
 #define NS_STYLE_OVERFLOW_SCROLL                2
 #define NS_STYLE_OVERFLOW_AUTO                  3
 #define NS_STYLE_OVERFLOW_CLIP                  4
 #define NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL 5
 #define NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL   6
 
+// See nsStyleDisplay.mOverflowClipBox
+#define NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX  0
+#define NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX  1
+
 // See nsStyleList
 #define NS_STYLE_LIST_STYLE_NONE                  0
 #define NS_STYLE_LIST_STYLE_DISC                  1
 #define NS_STYLE_LIST_STYLE_CIRCLE                2
 #define NS_STYLE_LIST_STYLE_SQUARE                3
 #define NS_STYLE_LIST_STYLE_DECIMAL               4
 #define NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO  5
 #define NS_STYLE_LIST_STYLE_LOWER_ROMAN           6
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2273,16 +2273,17 @@ nsStyleDisplay::nsStyleDisplay()
   mFloats = NS_STYLE_FLOAT_NONE;
   mOriginalFloats = mFloats;
   mBreakType = NS_STYLE_CLEAR_NONE;
   mBreakInside = NS_STYLE_PAGE_BREAK_AUTO;
   mBreakBefore = false;
   mBreakAfter = false;
   mOverflowX = NS_STYLE_OVERFLOW_VISIBLE;
   mOverflowY = NS_STYLE_OVERFLOW_VISIBLE;
+  mOverflowClipBox = NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX;
   mResize = NS_STYLE_RESIZE_NONE;
   mClipFlags = NS_STYLE_CLIP_AUTO;
   mClip.SetRect(0,0,0,0);
   mOpacity = 1.0f;
   mSpecifiedTransform = nullptr;
   mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin
   mTransformOrigin[1].SetPercentValue(0.5f);
   mTransformOrigin[2].SetCoordValue(0);
@@ -2329,16 +2330,17 @@ nsStyleDisplay::nsStyleDisplay(const nsS
   , mFloats(aSource.mFloats)
   , mOriginalFloats(aSource.mOriginalFloats)
   , mBreakType(aSource.mBreakType)
   , mBreakInside(aSource.mBreakInside)
   , mBreakBefore(aSource.mBreakBefore)
   , mBreakAfter(aSource.mBreakAfter)
   , mOverflowX(aSource.mOverflowX)
   , mOverflowY(aSource.mOverflowY)
+  , mOverflowClipBox(aSource.mOverflowClipBox)
   , mResize(aSource.mResize)
   , mClipFlags(aSource.mClipFlags)
   , mOrient(aSource.mOrient)
   , mMixBlendMode(aSource.mMixBlendMode)
   , mWillChangeBitField(aSource.mWillChangeBitField)
   , mWillChange(aSource.mWillChange)
   , mTouchAction(aSource.mTouchAction)
   , mBackfaceVisibility(aSource.mBackfaceVisibility)
@@ -2407,16 +2409,17 @@ nsChangeHint nsStyleDisplay::CalcDiffere
   // XXX the following is conservative, for now: changing float breaking shouldn't
   // necessarily require a repaint, reflow should suffice.
   if (mBreakType != aOther.mBreakType
       || mBreakInside != aOther.mBreakInside
       || mBreakBefore != aOther.mBreakBefore
       || mBreakAfter != aOther.mBreakAfter
       || mAppearance != aOther.mAppearance
       || mOrient != aOther.mOrient
+      || mOverflowClipBox != aOther.mOverflowClipBox
       || mClipFlags != aOther.mClipFlags || !mClip.IsEqualInterior(aOther.mClip))
     NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints,
                                        nsChangeHint_RepaintFrame));
 
   if (mOpacity != aOther.mOpacity) {
     NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
   }
 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1792,16 +1792,17 @@ struct nsStyleDisplay {
   uint8_t mOriginalFloats;      // [reset] saved mFloats for position:absolute/fixed;
                                 //         otherwise equal to mFloats
   uint8_t mBreakType;           // [reset] see nsStyleConsts.h NS_STYLE_CLEAR_*
   uint8_t mBreakInside;         // [reset] NS_STYLE_PAGE_BREAK_AUTO/AVOID
   bool mBreakBefore;    // [reset]
   bool mBreakAfter;     // [reset]
   uint8_t mOverflowX;           // [reset] see nsStyleConsts.h
   uint8_t mOverflowY;           // [reset] see nsStyleConsts.h
+  uint8_t mOverflowClipBox;     // [reset] see nsStyleConsts.h
   uint8_t mResize;              // [reset] see nsStyleConsts.h
   uint8_t mClipFlags;           // [reset] see nsStyleConsts.h
   uint8_t mOrient;              // [reset] see nsStyleConsts.h
   uint8_t mMixBlendMode;        // [reset] see nsStyleConsts.h
   uint8_t mWillChangeBitField;  // [reset] see nsStyleConsts.h. Stores a
                                 // bitfield representation of the properties
                                 // that are frequently queried. This should
                                 // match mWillChange. Also tracks if any of the
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4910,16 +4910,27 @@ if (SpecialPowers.getBoolPref("layout.cs
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "auto" ],
 		other_values: [ "scroll-position", "contents", "transform", "opacity", "scroll-position, transform", "transform, opacity", "contents, transform", "property-that-doesnt-exist-yet" ],
 		invalid_values: [ "none", "all", "default", "auto, scroll-position", "scroll-position, auto", "transform scroll-position", ",", "trailing," ]
 	};
 }
 
+if (SpecialPowers.getBoolPref("layout.css.overflow-clip-box.enabled")) {
+	gCSSProperties["overflow-clip-box"] = {
+		domProp: "overflowClipBox",
+		inherited: false,
+		type: CSS_TYPE_LONGHAND,
+		initial_values: [ "padding-box" ],
+		other_values: [ "content-box" ],
+		invalid_values: [ "none", "auto", "border-box", "0" ]
+	};
+}
+
 if (SpecialPowers.getBoolPref("layout.css.unset-value.enabled")) {
   gCSSProperties["animation-direction"].invalid_values.push("normal, unset");
   gCSSProperties["animation-name"].invalid_values.push("bounce, unset", "unset, bounce");
   gCSSProperties["-moz-border-bottom-colors"].invalid_values.push("red unset", "unset red");
   gCSSProperties["-moz-border-left-colors"].invalid_values.push("red unset", "unset red");
   gCSSProperties["border-radius"].invalid_values.push("unset 2px", "unset / 2px", "2px unset", "2px / unset");
   gCSSProperties["border-bottom-left-radius"].invalid_values.push("unset 2px", "2px unset");
   gCSSProperties["border-bottom-right-radius"].invalid_values.push("unset 2px", "2px unset");
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -98,36 +98,39 @@
 
 /* Miscellaneous */
 
 *|*::-moz-anonymous-block, *|*::-moz-cell-content {
   display: block !important;
   position: static !important;
   unicode-bidi: inherit;
   text-overflow: inherit;
+  overflow-clip-box: inherit;
 }
 
 *|*::-moz-anonymous-block, *|*::-moz-anonymous-positioned-block {
   /* we currently inherit from the inline that is split */
   outline: inherit;
   outline-offset: inherit;
   clip-path: inherit;
   filter: inherit;
   mask: inherit;
   opacity: inherit;
   text-decoration: inherit;
   -moz-box-ordinal-group: inherit !important;
+  overflow-clip-box: inherit;
 }
 
 *|*::-moz-xul-anonymous-block {
   display: block ! important;
   position: static ! important;
   float: none ! important;
   -moz-box-ordinal-group: inherit !important;
   text-overflow: inherit;
+  overflow-clip-box: inherit;
 }
 
 *|*::-moz-scrolled-content, *|*::-moz-scrolled-canvas,
 *|*::-moz-scrolled-page-sequence {
   /* e.g., text inputs, select boxes */
   padding: inherit;
   /* The display doesn't affect the kind of frame constructed here.  This just
      affects auto-width sizing of the block we create. */
@@ -146,16 +149,17 @@
   align-items: inherit;
   flex-direction: inherit;
   flex-wrap: inherit;
   justify-content: inherit;
   /* Do not change these. nsCSSFrameConstructor depends on them to create a good
      frame tree. */
   position: static !important;
   float: none !important;
+  overflow-clip-box: inherit;
 }
 
 *|*::-moz-viewport, *|*::-moz-viewport-scroll, *|*::-moz-canvas, *|*::-moz-scrolled-canvas {
   display: block !important;
   background-color: inherit;
 }
 
 *|*::-moz-viewport-scroll {
--- a/mfbt/RefPtr.h
+++ b/mfbt/RefPtr.h
@@ -69,21 +69,22 @@ class RefCounted
     RefCounted() : refCnt(0) { }
     ~RefCounted() {
       MOZ_ASSERT(refCnt == detail::DEAD);
     }
 
   public:
     // Compatibility with nsRefPtr.
     void AddRef() const {
+      MOZ_ASSERT(int32_t(refCnt) >= 0);
       ++refCnt;
     }
 
     void Release() const {
-      MOZ_ASSERT(refCnt > 0);
+      MOZ_ASSERT(int32_t(refCnt) > 0);
       if (0 == --refCnt) {
 #ifdef DEBUG
         refCnt = detail::DEAD;
 #endif
         delete static_cast<const T*>(this);
       }
     }
 
--- a/modules/libmar/sign/Makefile.in
+++ b/modules/libmar/sign/Makefile.in
@@ -1,12 +1,10 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # This makefile just builds support for reading archives.
-CFLAGS += -DMAR_NSS
-
 include $(topsrcdir)/config/rules.mk
 
 # The intermediate (.ii/.s) files for host and target can have the same name...
 # disable parallel builds
 .NOTPARALLEL:
--- a/modules/libmar/sign/moz.build
+++ b/modules/libmar/sign/moz.build
@@ -13,11 +13,12 @@ UNIFIED_SOURCES += [
 
 FORCE_STATIC_LIB = True
 
 LOCAL_INCLUDES += [
     '../src',
     '../verify',
 ]
 
+DEFINES['MAR_NSS'] = True
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     USE_STATIC_LIBS = True
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1825,16 +1825,19 @@ pref("layout.css.all-shorthand.enabled",
 
 // Is support for CSS variables enabled?
 #ifdef RELEASE_BUILD
 pref("layout.css.variables.enabled", false);
 #else
 pref("layout.css.variables.enabled", true);
 #endif
 
+// Is support for CSS overflow-clip-box enabled for non-UA sheets?
+pref("layout.css.overflow-clip-box.enabled", false);
+
 // pref for which side vertical scrollbars should be on
 // 0 = end-side in UI direction
 // 1 = end-side in document/content direction
 // 2 = right
 // 3 = left
 pref("layout.scrollbar.side", 0);
 
 // pref to control browser frame rate, in Hz. A value <= 0 means choose
--- a/testing/mozbase/mozrunner/setup.py
+++ b/testing/mozbase/mozrunner/setup.py
@@ -1,17 +1,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import sys
 from setuptools import setup
 
 PACKAGE_NAME = 'mozrunner'
-PACKAGE_VERSION = '5.34'
+PACKAGE_VERSION = '5.35'
 
 desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
 
 deps = ['mozcrash >= 0.11',
         'mozdevice >= 0.30',
         'mozfile >= 1.0',
         'mozinfo >= 0.7',
         'mozlog >= 1.5',
--- a/toolkit/components/contentprefs/ContentPrefService2.jsm
+++ b/toolkit/components/contentprefs/ContentPrefService2.jsm
@@ -35,16 +35,71 @@ Cu.import("resource://gre/modules/Conten
 function ContentPrefService2(cps) {
   this._cps = cps;
   this._cache = cps._cache;
   this._pbStore = cps._privModeStorage;
 }
 
 ContentPrefService2.prototype = {
 
+  getByName: function CPS2_getByName(name, context, callback) {
+    checkNameArg(name);
+    checkCallbackArg(callback, true);
+
+    // Some prefs may be in both the database and the private browsing store.
+    // Notify the caller of such prefs only once, using the values from private
+    // browsing.
+    let pbPrefs = new ContentPrefStore();
+    if (context && context.usePrivateBrowsing) {
+      for (let [sgroup, sname, val] in this._pbStore) {
+        if (sname == name) {
+          pbPrefs.set(sgroup, sname, val);
+        }
+      }
+    }
+
+    let stmt1 = this._stmt(
+      "SELECT groups.name AS grp, prefs.value AS value",
+      "FROM prefs",
+      "JOIN settings ON settings.id = prefs.settingID",
+      "JOIN groups ON groups.id = prefs.groupID",
+      "WHERE settings.name = :name"
+    );
+    stmt1.params.name = name;
+
+    let stmt2 = this._stmt(
+      "SELECT NULL AS grp, prefs.value AS value",
+      "FROM prefs",
+      "JOIN settings ON settings.id = prefs.settingID",
+      "WHERE settings.name = :name AND prefs.groupID ISNULL"
+    );
+    stmt2.params.name = name;
+
+    this._execStmts([stmt1, stmt2], {
+      onRow: function onRow(row) {
+        let grp = row.getResultByName("grp");
+        let val = row.getResultByName("value");
+        this._cache.set(grp, name, val);
+        if (!pbPrefs.has(grp, name))
+          cbHandleResult(callback, new ContentPref(grp, name, val));
+      },
+      onDone: function onDone(reason, ok, gotRow) {
+        if (ok) {
+          for (let [pbGroup, pbName, pbVal] in pbPrefs) {
+            cbHandleResult(callback, new ContentPref(pbGroup, pbName, pbVal));
+          }
+        }
+        cbHandleCompletion(callback, reason);
+      },
+      onError: function onError(nsresult) {
+        cbHandleError(callback, nsresult);
+      }
+    });
+  },
+
   getByDomainAndName: function CPS2_getByDomainAndName(group, name, context,
                                                        callback) {
     checkGroupArg(group);
     this._get(group, name, false, context, callback);
   },
 
   getBySubdomainAndName: function CPS2_getBySubdomainAndName(group, name,
                                                              context,
--- a/toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js
+++ b/toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js
@@ -165,9 +165,31 @@ let tests = [
         do_check_true(!!fetchedPref);
         do_check_eq(fetchedPref.value, 2);
         next();
       },
     });
 
     yield;
   },
+
+  function get_nameOnly() {
+    yield set("a.com", "foo", 1);
+    yield set("a.com", "bar", 2);
+    yield set("b.com", "foo", 3);
+    yield setGlobal("foo", 4);
+
+    yield getOKEx("getByName", ["foo", undefined], [
+      {"domain": "a.com", "name": "foo", "value": 1},
+      {"domain": "b.com", "name": "foo", "value": 3},
+      {"domain": null, "name": "foo", "value": 4}
+    ]);
+
+    let context = { usePrivateBrowsing: true };
+    yield set("b.com", "foo", 5, context);
+
+    yield getOKEx("getByName", ["foo", context], [
+      {"domain": "a.com", "name": "foo", "value": 1},
+      {"domain": null, "name": "foo", "value": 4},
+      {"domain": "b.com", "name": "foo", "value": 5}
+    ]);
+  }
 ];
--- a/widget/windows/winrt/FrameworkView.cpp
+++ b/widget/windows/winrt/FrameworkView.cpp
@@ -34,16 +34,18 @@ using namespace Microsoft::WRL::Wrappers
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
 
 // statics
 bool FrameworkView::sKeyboardIsVisible = false;
 Rect FrameworkView::sKeyboardRect;
+HSTRING FrameworkView::sActivationURI = NULL;
+ApplicationExecutionState FrameworkView::sPreviousExecutionState;
 nsTArray<nsString>* sSettingsArray;
 
 FrameworkView::FrameworkView(MetroApp* aMetroApp) :
   mDPI(-1.0f),
   mWidget(nullptr),
   mShuttingDown(false),
   mMetroApp(aMetroApp),
   mWindow(nullptr),
@@ -108,16 +110,17 @@ FrameworkView::Run()
   // Initialize XPCOM, create mWidget and go! We get a
   // callback in MetroAppShell::Run, in which we kick
   // off normal browser execution / event dispatching.
   mMetroApp->Run();
 
   // Gecko is completely shut down at this point.
   WinUtils::Log("Exiting FrameworkView::Run()");
 
+  WindowsDeleteString(sActivationURI);
   return S_OK;
 }
 
 HRESULT
 FrameworkView::ActivateView()
 {
   LogFunction();
 
@@ -386,30 +389,24 @@ FrameworkView::OnActivated(ICoreApplicat
                            IActivatedEventArgs* aArgs)
 {
   LogFunction();
 
   if (mShuttingDown) {
     return S_OK;
   }
 
-  aArgs->get_PreviousExecutionState(&mPreviousExecutionState);
-  bool startup = mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_Terminated ||
-                 mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_ClosedByUser ||
-                 mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_NotRunning;
+  aArgs->get_PreviousExecutionState(&sPreviousExecutionState);
+  bool startup = sPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_Terminated ||
+                 sPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_ClosedByUser ||
+                 sPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_NotRunning;
   ProcessActivationArgs(aArgs, startup);
   return S_OK;
 }
 
-int
-FrameworkView::GetPreviousExecutionState()
-{
-  return mPreviousExecutionState;
-}
-
 HRESULT
 FrameworkView::OnSoftkeyboardHidden(IInputPane* aSender,
                                     IInputPaneVisibilityEventArgs* aArgs)
 {
   LogFunction();
   sKeyboardIsVisible = false;
   memset(&sKeyboardRect, 0, sizeof(Rect));
   MetroUtils::FireObserver("metro_softkeyboard_hidden");
--- a/widget/windows/winrt/FrameworkView.h
+++ b/widget/windows/winrt/FrameworkView.h
@@ -75,28 +75,33 @@ public:
   STDMETHODIMP SetWindow(ICoreWindow* aWindow);
   STDMETHODIMP Load(HSTRING aEntryPoint);
   STDMETHODIMP Run();
   STDMETHODIMP Uninitialize();
 
   HRESULT ActivateView();
 
   // Public apis for MetroWidget
-  int GetPreviousExecutionState();
   float GetDPI() { return mDPI; }
   ICoreWindow* GetCoreWindow() { return mWindow.Get(); }
   void SetWidget(MetroWidget* aWidget);
   MetroWidget* GetWidget() { return mWidget.Get(); }
   void GetBounds(nsIntRect &aRect);
-  void GetActivationURI(nsAString &aActivationURI) { aActivationURI = mActivationURI; }
   void SetCursor(ABI::Windows::UI::Core::CoreCursorType aCursorType, DWORD aCustomId = 0);
   void ClearCursor();
   bool IsEnabled() const;
   bool IsVisible() const;
 
+  // Activation apis for nsIWinMetroUtils
+  static int GetPreviousExecutionState() { return sPreviousExecutionState; }
+  static void GetActivationURI(nsAString &aActivationURI) {
+    unsigned int length;
+    aActivationURI = WindowsGetStringRawBuffer(sActivationURI, &length);
+  }
+
   // Soft keyboard info for nsIWinMetroUtils
   static bool IsKeyboardVisible() { return sKeyboardIsVisible; }
   static ABI::Windows::Foundation::Rect KeyboardVisibleRect() { return sKeyboardRect; }
 
   // MetroApp apis
   void SetupContracts();
   void Shutdown();
 
@@ -170,30 +175,31 @@ private:
   EventRegistrationToken mAutomationProviderRequested;
   EventRegistrationToken mDataTransferRequested;
   EventRegistrationToken mSearchQuerySubmitted;
   EventRegistrationToken mPlayToRequested;
   EventRegistrationToken mSettingsPane;
   EventRegistrationToken mPrintManager;
 
 private:
-  ABI::Windows::ApplicationModel::Activation::ApplicationExecutionState mPreviousExecutionState;
   nsIntRect mWindowBounds; // in device-pixel coordinates
   float mDPI;
   bool mShuttingDown;
-  nsAutoString mActivationURI;
   nsAutoString mActivationCommandLine;
   Microsoft::WRL::ComPtr<IInspectable> mAutomationProvider;
   //Microsoft::WRL::ComPtr<ID2D1PrintControl> mD2DPrintControl;
   // Private critical section protects D2D device context for on-screen
   // rendering from that for print/preview in the different thread.
   //Microsoft::WRL::ComPtr<IWICImagingFactory2> mWicFactory;
   Microsoft::WRL::ComPtr<MetroApp> mMetroApp;
   Microsoft::WRL::ComPtr<ICoreWindow> mWindow;
   Microsoft::WRL::ComPtr<MetroWidget> mWidget;
   Microsoft::WRL::ComPtr<MetroInput> mMetroInput;
+  bool mWinVisible;
+  bool mWinActiveState;
+
   static bool sKeyboardIsVisible;
   static Rect sKeyboardRect;
-  bool mWinVisible;
-  bool mWinActiveState;
+  static HSTRING sActivationURI;
+  static ABI::Windows::ApplicationModel::Activation::ApplicationExecutionState sPreviousExecutionState;
 };
 
 } } }
--- a/widget/windows/winrt/MetroApp.cpp
+++ b/widget/windows/winrt/MetroApp.cpp
@@ -46,22 +46,27 @@ bool MetroApp::sGeckoShuttingDown = fals
 
 ////////////////////////////////////////////////////
 // IFrameworkViewSource impl.
 
 // Called after CoreApplication::Run(app)
 HRESULT
 MetroApp::CreateView(ABI::Windows::ApplicationModel::Core::IFrameworkView **aViewProvider)
 {
-  // This entry point is called on the metro main thread, but the thread won't be
-  // recognized as such until after Initialize is called below. XPCOM has not gone
-  // through startup at this point.
+  // This entry point is called on the metro main thread, but the thread won't
+  // be recognized as such until after Run() is called below. XPCOM has not
+  // gone through startup at this point.
+
+  // Note that we create the view which creates our native window for us. The
+  // gecko widget gets created by gecko, and the two get hooked up later in
+  // MetroWidget::Create().
 
   LogFunction();
 
+  sFrameworkView = Make<FrameworkView>(this);
   sFrameworkView.Get()->AddRef();
   *aViewProvider = sFrameworkView.Get();
   return !sFrameworkView ? E_FAIL : S_OK;
 }
 
 ////////////////////////////////////////////////////
 // MetroApp impl.
 
@@ -129,16 +134,41 @@ MetroApp::CoreExit()
   HStringReference className(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication);
   hr = GetActivationFactory(className.Get(), coreExit.GetAddressOf());
   NS_ASSERTION(SUCCEEDED(hr), "Activation of ICoreApplicationExit");
   if (SUCCEEDED(hr)) {
     coreExit->Exit();
   }
 }
 
+void
+MetroApp::ActivateBaseView()
+{
+  if (sFrameworkView) {
+    sFrameworkView->ActivateView();
+  }
+}
+
+/*
+ * TBD: when we support multiple widgets, we'll need a way to sync up the view
+ * created in CreateView with the widget gecko creates. Currently we only have
+ * one view (sFrameworkView) and one main widget.
+ */
+void
+MetroApp::SetWidget(MetroWidget* aPtr)
+{
+  LogThread();
+
+  NS_ASSERTION(aPtr, "setting null base widget?");
+
+  // Both of these calls AddRef the ptr we pass in
+  aPtr->SetView(sFrameworkView.Get());
+  sFrameworkView->SetWidget(aPtr);
+}
+
 ////////////////////////////////////////////////////
 // MetroApp events
 
 HRESULT
 MetroApp::OnSuspending(IInspectable* aSender, ISuspendingEventArgs* aArgs)
 {
   LogThread();
   PostSuspendResumeProcessNotification(true);
@@ -159,29 +189,16 @@ MetroApp::OnAsyncTileCreated(ABI::Window
 {
   WinUtils::Log("Async operation status: %d", aStatus);
   MetroUtils::FireObserver("metro_on_async_tile_created");
   return S_OK;
 }
 
 // static
 void
-MetroApp::SetBaseWidget(MetroWidget* aPtr)
-{
-  LogThread();
-
-  NS_ASSERTION(aPtr, "setting null base widget?");
-
-  // Both of these calls AddRef the ptr we pass in
-  aPtr->SetView(sFrameworkView.Get());
-  sFrameworkView->SetWidget(aPtr);
-}
-
-// static
-void
 MetroApp::PostSuspendResumeProcessNotification(const bool aIsSuspend)
 {
   static bool isSuspend = false;
   if (isSuspend == aIsSuspend) {
     return;
   }
   isSuspend = aIsSuspend;
   MetroUtils::FireObserver(aIsSuspend ? "suspend_process_notification" :
@@ -246,19 +263,17 @@ XRE_MetroCoreApplicationRun()
     sessionBAK->AppendNative(nsDependentCString("sessionstore.bak"));
     bool exists;
     if (NS_SUCCEEDED(sessionBAK->Exists(&exists)) && exists) {
       sessionBAK->Remove(false);
     }
     return false;
   }
 
-  sFrameworkView = Make<FrameworkView>(sMetroApp.Get());
   hr = sCoreApp->Run(sMetroApp.Get());
-  sFrameworkView = nullptr;
 
   WinUtils::Log("Exiting CoreApplication::Run");
 
   sCoreApp = nullptr;
   sMetroApp = nullptr;
 
   return true;
 }
--- a/widget/windows/winrt/MetroApp.h
+++ b/widget/windows/winrt/MetroApp.h
@@ -14,18 +14,16 @@
 #include <Windows.Applicationmodel.Activation.h>
 
 class MetroWidget;
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
 
-class FrameworkView;
-
 class MetroApp : public Microsoft::WRL::RuntimeClass<ABI::Windows::ApplicationModel::Core::IFrameworkViewSource>
 {
   InspectableClass(L"MetroApp", TrustLevel::BaseTrust)
 
   typedef ABI::Windows::UI::Core::CoreDispatcherPriority CoreDispatcherPriority;
   typedef ABI::Windows::ApplicationModel::Activation::LaunchActivatedEventArgs LaunchActivatedEventArgs;
   typedef ABI::Windows::ApplicationModel::ISuspendingEventArgs ISuspendingEventArgs;
   typedef ABI::Windows::ApplicationModel::Core::IFrameworkView IFrameworkView;
@@ -40,22 +38,24 @@ public:
   HRESULT OnResuming(IInspectable* aSender, IInspectable* aArgs);
 
   // nsIWinMetroUtils tile related async callbacks
   HRESULT OnAsyncTileCreated(ABI::Windows::Foundation::IAsyncOperation<bool>* aOperation, AsyncStatus aStatus);
 
   void Run();
   void CoreExit();
   void Shutdown();
+  void ActivateBaseView();
 
   // Set when gecko enters xpcom shutdown.
   static bool sGeckoShuttingDown;
 
   // Shared pointers between framework and widget
-  static void SetBaseWidget(MetroWidget* aPtr);
+  void SetWidget(MetroWidget* aPtr);
+
   static void PostSuspendResumeProcessNotification(bool aIsSuspend);
   static void PostSleepWakeNotification(bool aIsSuspend);
 
 private:
   EventRegistrationToken mSuspendEvent;
   EventRegistrationToken mResumeEvent;
 };
 
--- a/widget/windows/winrt/MetroAppShell.cpp
+++ b/widget/windows/winrt/MetroAppShell.cpp
@@ -37,17 +37,16 @@ using namespace ABI::Windows::Foundation
 // up to date. This is the maximum amount of time we'll agree to spend in
 // NS_ProcessPendingEvents.
 #define PURGE_MAX_TIMEOUT 50
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
 extern ComPtr<MetroApp> sMetroApp;
-extern ComPtr<FrameworkView> sFrameworkView;
 } } }
 
 namespace mozilla {
 namespace widget {
 // pulled from win32 app shell
 extern UINT sAppShellGeckoMsgId;
 } }
 
@@ -237,17 +236,17 @@ MetroAppShell::Run(void)
         sWakeLockListener = new WakeLockListener();
         sPowerManagerService->AddWakeLockListener(sWakeLockListener);
       }
       else {
         NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!");
       }
 
       mozilla::widget::StartAudioSession();
-      sFrameworkView->ActivateView();
+      sMetroApp->ActivateBaseView();
       rv = nsBaseAppShell::Run();
       mozilla::widget::StopAudioSession();
 
       if (sPowerManagerService) {
         sPowerManagerService->RemoveWakeLockListener(sWakeLockListener);
 
         sPowerManagerService = nullptr;
         sWakeLockListener = nullptr;
--- a/widget/windows/winrt/MetroContracts.cpp
+++ b/widget/windows/winrt/MetroContracts.cpp
@@ -56,17 +56,17 @@ FrameworkView::SearchActivated(ComPtr<IS
   HString data;
   AssertHRESULT(aArgs->get_QueryText(data.GetAddressOf()));
   if (WindowsIsStringEmpty(data.Get()))
     return;
 
   unsigned int length;
   WinUtils::LogW(L"SearchActivated text=%s", data.GetRawBuffer(&length));
   if (aStartup) {
-    mActivationURI = data.GetRawBuffer(&length);
+    WindowsDuplicateString(data.Get(), &sActivationURI);
   } else {
     PerformURILoadOrSearch(data);
   }
 }
 
 void
 FrameworkView::FileActivated(ComPtr<IFileActivatedEventArgs>& aArgs, bool aStartup)
 {
@@ -76,41 +76,40 @@ FrameworkView::FileActivated(ComPtr<IFil
   ComPtr<IVectorView<ABI::Windows::Storage::IStorageItem*>> list;
   AssertHRESULT(aArgs->get_Files(list.GetAddressOf()));
   ComPtr<ABI::Windows::Storage::IStorageItem> item;
   AssertHRESULT(list->GetAt(0, item.GetAddressOf()));
   HString filePath;
   AssertHRESULT(item->get_Path(filePath.GetAddressOf()));
 
   if (aStartup) {
-    unsigned int length;
-    mActivationURI = filePath.GetRawBuffer(&length);
+    WindowsDuplicateString(filePath.Get(), &sActivationURI);
   } else {
     PerformURILoad(filePath);
   }
 }
 
 void
 FrameworkView::LaunchActivated(ComPtr<ILaunchActivatedEventArgs>& aArgs, bool aStartup)
 {
   if (!aArgs)
     return;
   HString data;
   AssertHRESULT(aArgs->get_Arguments(data.GetAddressOf()));
   if (WindowsIsStringEmpty(data.Get()))
     return;
 
   // If we're being launched from a secondary tile then we have a 2nd command line param of -url
-  // and a third of the secondary tile.  We want it in mActivationURI so that browser.js will
+  // and a third of the secondary tile.  We want it in sActivationURI so that browser.js will
   // load it in without showing the start UI.
   int argc;
   unsigned int length;
   LPWSTR* argv = CommandLineToArgvW(data.GetRawBuffer(&length), &argc);
   if (aStartup && argc == 2 && !wcsicmp(argv[0], L"-url")) {
-    mActivationURI = argv[1];
+    WindowsCreateString(argv[1], wcslen(argv[1]), &sActivationURI);
   } else {
     // Some other command line or this is not a startup.
     // If it is startup we process it later when XPCOM is initialilzed.
     mActivationCommandLine = data.GetRawBuffer(&length);
     if (!aStartup) {
       ProcessLaunchArguments();
     }
   }
@@ -172,18 +171,17 @@ FrameworkView::ProcessActivationArgs(IAc
       return;
 
     HString data;
     AssertHRESULT(uri->get_AbsoluteUri(data.GetAddressOf()));
     if (WindowsIsStringEmpty(data.Get()))
       return;
 
     if (aStartup) {
-      unsigned int length;
-      mActivationURI = data.GetRawBuffer(&length);
+      WindowsDuplicateString(data.Get(), &sActivationURI);
     } else {
       PerformURILoad(data);
     }
   } else if (kind == ActivationKind::ActivationKind_Search) {
     WinUtils::Log("Activation argument kind: Search");
     ComPtr<ISearchActivatedEventArgs> searchArgs;
     args.As(&searchArgs);
     SearchActivated(searchArgs, aStartup);
--- a/widget/windows/winrt/MetroWidget.cpp
+++ b/widget/windows/winrt/MetroWidget.cpp
@@ -77,16 +77,17 @@ UINT sDefaultBrowserMsgId = RegisterWind
 } }
 
 // WM_GETOBJECT id pulled from uia headers
 #define UiaRootObjectId -25
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
+extern ComPtr<MetroApp> sMetroApp;
 extern ComPtr<IUIABridge> gProviderRoot;
 } } }
 
 namespace {
 
   void SendInputs(uint32_t aModifiers, INPUT* aExtraInputs, uint32_t aExtraInputsLen)
   {
     // keySequence holds the virtual key values of each of the keys we intend
@@ -248,17 +249,17 @@ MetroWidget::Create(nsIWidget *aParent,
     // can be created.
     NS_WARNING("New eWindowType_toplevel window requested after FrameworkView widget created.");
     NS_WARNING("Widget created but the physical window does not exist! Fix me!");
     return NS_OK;
   }
 
   // the main widget gets created first
   gTopLevelAssigned = true;
-  MetroApp::SetBaseWidget(this);
+  sMetroApp->SetWidget(this);
   WinUtils::SetNSWindowBasePtr(mWnd, this);
 
   if (mWidgetListener) {
     mWidgetListener->WindowActivated();
   }
 
   return NS_OK;
 }
--- a/widget/windows/winrt/nsWinMetroUtils.cpp
+++ b/widget/windows/winrt/nsWinMetroUtils.cpp
@@ -22,17 +22,16 @@ using namespace Microsoft::WRL;
 using namespace Microsoft::WRL::Wrappers;
 using namespace mozilla::widget::winrt;
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
 extern ComPtr<MetroApp> sMetroApp;
 extern nsTArray<nsString>* sSettingsArray;
-extern ComPtr<FrameworkView> sFrameworkView;
 } } }
 
 namespace mozilla {
 namespace widget {
 
 bool nsWinMetroUtils::sUpdatePending = false;
 
 NS_IMPL_ISUPPORTS1(nsWinMetroUtils, nsIWinMetroUtils)
@@ -59,17 +58,17 @@ nsWinMetroUtils::~nsWinMetroUtils()
 NS_IMETHODIMP
 nsWinMetroUtils::PinTileAsync(const nsAString &aTileID,
                               const nsAString &aShortName,
                               const nsAString &aDisplayName,
                               const nsAString &aActivationArgs,
                               const nsAString &aTileImage,
                               const nsAString &aSmallTileImage)
 {
-  if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
+  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
     NS_WARNING("PinTileAsync can't be called on the desktop.");
     return NS_ERROR_FAILURE;
   }
   HRESULT hr;
 
   HString logoStr, smallLogoStr, displayName, shortName;
 
   logoStr.Set(aTileImage.BeginReading());
@@ -112,17 +111,17 @@ nsWinMetroUtils::PinTileAsync(const nsAS
 /**
  * Unpins a tile from the Windows 8 start screen.
  *
  * @param aTileID An existing ID which was previously pinned
  */
 NS_IMETHODIMP
 nsWinMetroUtils::UnpinTileAsync(const nsAString &aTileID)
 {
-  if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
+  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
     NS_WARNING("UnpinTileAsync can't be called on the desktop.");
     return NS_ERROR_FAILURE;
   }
   HRESULT hr;
   HString tileIdStr;
   tileIdStr.Set(aTileID.BeginReading());
 
   ComPtr<ISecondaryTileFactory> tileFactory;
@@ -146,17 +145,17 @@ nsWinMetroUtils::UnpinTileAsync(const ns
  * Determines if a tile is pinned to the Windows 8 start screen.
  *
  * @param aTileID   An ID which may have been pinned with pinTileAsync
  * @param aIsPinned Out parameter for determining if the tile is pinned or not
  */
 NS_IMETHODIMP
 nsWinMetroUtils::IsTilePinned(const nsAString &aTileID, bool *aIsPinned)
 {
-  if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
+  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
     NS_WARNING("IsTilePinned can't be called on the desktop.");
     return NS_ERROR_FAILURE;
   }
   NS_ENSURE_ARG_POINTER(aIsPinned);
 
   HRESULT hr;
   HString tileIdStr;
   tileIdStr.Set(aTileID.BeginReading());
@@ -225,17 +224,17 @@ nsWinMetroUtils::ShowNativeToast(const n
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::ShowSettingsFlyout()
 {
-  if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
+  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
     NS_WARNING("Settings flyout can't be shown on the desktop.");
     return NS_ERROR_FAILURE;
   }
 
   HRESULT hr = MetroUtils::ShowSettingsFlyout();
   return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
 }
 
@@ -245,67 +244,65 @@ nsWinMetroUtils::GetImmersive(bool *aIme
   *aImersive =
     XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::GetActivationURI(nsAString &aActivationURI)
 {
-  if (!sFrameworkView) {
-    NS_WARNING("GetActivationURI used before view is created!");
-    return NS_OK;
+  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
+    return NS_ERROR_FAILURE;
   }
-  sFrameworkView->GetActivationURI(aActivationURI);
+  FrameworkView::GetActivationURI(aActivationURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::GetPreviousExecutionState(int32_t *out)
 {
-  if (!sFrameworkView) {
-    NS_WARNING("GetPreviousExecutionState used before view is created!");
-    return NS_OK;
+  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
+    return NS_ERROR_FAILURE;
   }
-  *out = sFrameworkView->GetPreviousExecutionState();
+  *out = FrameworkView::GetPreviousExecutionState();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::GetKeyboardVisible(bool *aImersive)
 {
-  *aImersive = mozilla::widget::winrt::FrameworkView::IsKeyboardVisible();
+  *aImersive = FrameworkView::IsKeyboardVisible();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::GetKeyboardX(uint32_t *aX)
 {
-  *aX = (uint32_t)floor(mozilla::widget::winrt::FrameworkView::KeyboardVisibleRect().X);
+  *aX = static_cast<uint32_t>(floor(FrameworkView::KeyboardVisibleRect().X));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::GetKeyboardY(uint32_t *aY)
 {
-  *aY = (uint32_t)floor(mozilla::widget::winrt::FrameworkView::KeyboardVisibleRect().Y);
+  *aY = static_cast<uint32_t>(floor(FrameworkView::KeyboardVisibleRect().Y));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::GetKeyboardWidth(uint32_t *aWidth)
 {
-  *aWidth = (uint32_t)ceil(mozilla::widget::winrt::FrameworkView::KeyboardVisibleRect().Width);
+  *aWidth = static_cast<uint32_t>(ceil(FrameworkView::KeyboardVisibleRect().Width));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::GetKeyboardHeight(uint32_t *aHeight)
 {
-  *aHeight = (uint32_t)ceil(mozilla::widget::winrt::FrameworkView::KeyboardVisibleRect().Height);
+  *aHeight = static_cast<uint32_t>(ceil(FrameworkView::KeyboardVisibleRect().Height));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWinMetroUtils::AddSettingsPanelEntry(const nsAString &aLabel, uint32_t *aId)
 {
   NS_ENSURE_ARG_POINTER(aId);
   if (!sSettingsArray)
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -872,25 +872,17 @@ nsCycleCollectionParticipant*
 CycleCollectedJSRuntime::ZoneParticipant()
 {
     return &mJSZoneCycleCollectorGlobal;
 }
 
 nsresult
 CycleCollectedJSRuntime::TraverseRoots(nsCycleCollectionNoteRootCallback &aCb)
 {
-  static bool gcHasRun = false;
-  if (!gcHasRun) {
-    uint32_t gcNumber = JS_GetGCParameter(mJSRuntime, JSGC_NUMBER);
-    if (!gcNumber) {
-      // Cannot cycle collect if GC has not run first!
-      MOZ_CRASH();
-    }
-    gcHasRun = true;
-  }
+  MOZ_ASSERT(!NeedCollect(), "Cannot cycle collect if GC has not run first!");
 
   TraverseNativeRoots(aCb);
 
   NoteWeakMapsTracer trc(mJSRuntime, TraceWeakMapping, aCb);
   js::TraceWeakMaps(&trc);
 
   return NS_OK;
 }