Merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 29 Dec 2015 12:39:59 +0100
changeset 277842 b50e4b404973b62b34bf4a182d7bd9990b654b8a
parent 277841 065c3aa884c6a08de85d679ea11f264ed8cf4e22 (current diff)
parent 277774 9ddf0da90fb3bc1ae29966dc596013fc54a44bd2 (diff)
child 277843 22ce7a979a815bc394622cb2ca2f1ebc9334f22a
push id69628
push usercbook@mozilla.com
push dateWed, 30 Dec 2015 11:16:09 +0000
treeherdermozilla-inbound@b493cf33851f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to b2g-inbound
toolkit/components/jsdownloads/test/unit/tail.js
--- a/browser/base/content/test/general/mochitest.ini
+++ b/browser/base/content/test/general/mochitest.ini
@@ -24,17 +24,17 @@ support-files =
   offlineEvent.cacheManifest^headers^
   offlineEvent.html
   subtst_contextmenu.html
   video.ogg
 
 [test_bug364677.html]
 [test_bug395533.html]
 [test_contextmenu.html]
-skip-if = toolkit == "gtk2" || toolkit == "gtk3" || (os == 'mac' && os_version != '10.6') # disabled on Linux due to bug 513558, on Mac after 10.6 due to bug 792304
+skip-if = toolkit == "gtk2" || toolkit == "gtk3" || (os == 'mac' && os_version != '10.6') || e10s # disabled on Linux due to bug 513558, on Mac after 10.6 due to bug 792304
 [test_contextmenu_input.html]
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" || e10s # disabled on Linux due to bug 513558
 [test_feed_discovery.html]
 skip-if = e10s
 [test_offlineNotification.html]
 skip-if = buildapp == 'mulet' || e10s # Bug 1066070 - I don't think either popup notifications nor addon install stuff works?
 [test_offline_gzip.html]
 skip-if = buildapp == 'mulet' || e10s # Bug 1066070 - I don't think either popup notifications nor addon install stuff works?
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -687,17 +687,18 @@ toolbarpaletteitem[place="palette"] > to
   padding: 30px 15px 15px 15px;
 }
 
 .PanelUI-remotetabs-prefs-button {
   -moz-appearance: none;
   background-color: #0096dd;
   color: white;
   border-radius: 2px;
-  margin: 10px;
+  margin-top: 10px;
+  margin-bottom: 10px;
   padding: 8px;
   text-shadow: none;
   min-width: 200px;
 }
 
 .PanelUI-remotetabs-prefs-button:hover,
 .PanelUI-remotetabs-prefs-button:hover:active {
   background-color: #018acb;
--- a/dom/audiochannel/AudioChannelAgent.cpp
+++ b/dom/audiochannel/AudioChannelAgent.cpp
@@ -36,17 +36,16 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioChannelAgent)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioChannelAgent)
 
 AudioChannelAgent::AudioChannelAgent()
   : mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR)
   , mInnerWindowID(0)
   , mIsRegToService(false)
-  , mNotifyPlayback(false)
 {
 }
 
 AudioChannelAgent::~AudioChannelAgent()
 {
   Shutdown();
 }
 
@@ -203,18 +202,17 @@ AudioChannelAgent::InitInternal(nsIDOMWi
   MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
          ("AudioChannelAgent, InitInternal, this = %p, type = %d, "
           "owner = %p, hasCallback = %d\n", this, mAudioChannelType,
           mWindow.get(), (!!mCallback || !!mWeakCallback)));
 
   return NS_OK;
 }
 
-NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(uint32_t aNotifyPlayback,
-                                                      float *aVolume,
+NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(float *aVolume,
                                                       bool* aMuted)
 {
   MOZ_ASSERT(aVolume);
   MOZ_ASSERT(aMuted);
 
   // Window-less AudioChannelAgents are muted by default.
   if (!mWindow) {
     *aVolume = 0;
@@ -223,43 +221,42 @@ NS_IMETHODIMP AudioChannelAgent::NotifyS
   }
 
   RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
   if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
       service == nullptr || mIsRegToService) {
     return NS_ERROR_FAILURE;
   }
 
-  service->RegisterAudioChannelAgent(this, aNotifyPlayback,
+  service->RegisterAudioChannelAgent(this,
     static_cast<AudioChannel>(mAudioChannelType));
 
   service->GetState(mWindow, mAudioChannelType, aVolume, aMuted);
 
   MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
          ("AudioChannelAgent, NotifyStartedPlaying, this = %p, mute = %d, "
           "volume = %f\n", this, *aMuted, *aVolume));
 
-  mNotifyPlayback = aNotifyPlayback;
   mIsRegToService = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP AudioChannelAgent::NotifyStoppedPlaying()
 {
   if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
       !mIsRegToService) {
     return NS_ERROR_FAILURE;
   }
 
   MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
          ("AudioChannelAgent, NotifyStoppedPlaying, this = %p\n", this));
 
   RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
   if (service) {
-    service->UnregisterAudioChannelAgent(this, mNotifyPlayback);
+    service->UnregisterAudioChannelAgent(this);
   }
 
   mIsRegToService = false;
   return NS_OK;
 }
 
 already_AddRefed<nsIAudioChannelAgentCallback>
 AudioChannelAgent::GetCallback()
@@ -295,22 +292,33 @@ AudioChannelAgent::WindowVolumeChanged()
 }
 
 uint64_t
 AudioChannelAgent::WindowID() const
 {
   return mWindow ? mWindow->WindowID() : 0;
 }
 
+uint64_t
+AudioChannelAgent::InnerWindowID() const
+{
+  return mInnerWindowID;
+}
+
 void
-AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID)
+AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID,
+                                             bool aCapture)
 {
   if (aInnerWindowID != mInnerWindowID) {
     return;
   }
 
   nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
   if (!callback) {
     return;
   }
 
-  callback->WindowAudioCaptureChanged();
+  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
+         ("AudioChannelAgent, WindowAudioCaptureChanged, this = %p, "
+          "capture = %d\n", this, aCapture));
+
+  callback->WindowAudioCaptureChanged(aCapture);
 }
--- a/dom/audiochannel/AudioChannelAgent.h
+++ b/dom/audiochannel/AudioChannelAgent.h
@@ -29,24 +29,25 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIAUDIOCHANNELAGENT
 
   NS_DECL_CYCLE_COLLECTION_CLASS(AudioChannelAgent)
 
   AudioChannelAgent();
 
   void WindowVolumeChanged();
-  void WindowAudioCaptureChanged(uint64_t aInnerWindowID);
+  void WindowAudioCaptureChanged(uint64_t aInnerWindowID, bool aCapture);
 
   nsPIDOMWindow* Window() const
   {
     return mWindow;
   }
 
   uint64_t WindowID() const;
+  uint64_t InnerWindowID() const;
 
 private:
   virtual ~AudioChannelAgent();
 
   // Returns mCallback if that's non-null, or otherwise tries to get an
   // nsIAudioChannelAgentCallback out of mWeakCallback.
   already_AddRefed<nsIAudioChannelAgentCallback> GetCallback();
 
@@ -61,16 +62,15 @@ private:
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsCOMPtr<nsIAudioChannelAgentCallback> mCallback;
 
   nsWeakPtr mWeakCallback;
 
   int32_t mAudioChannelType;
   uint64_t mInnerWindowID;
   bool mIsRegToService;
-  bool mNotifyPlayback;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 
 #endif
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -263,17 +263,16 @@ AudioChannelService::AudioChannelService
 }
 
 AudioChannelService::~AudioChannelService()
 {
 }
 
 void
 AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
-                                               uint32_t aNotifyPlayback,
                                                AudioChannel aChannel)
 {
   uint64_t windowID = aAgent->WindowID();
   AudioChannelWindow* winData = GetWindowData(windowID);
   if (!winData) {
     winData = new AudioChannelWindow(windowID);
     mWindows.AppendElement(winData);
   }
@@ -284,29 +283,34 @@ AudioChannelService::RegisterAudioChanne
   ++winData->mChannels[(uint32_t)aChannel].mNumberOfAgents;
 
   // The first one, we must inform the BrowserElementAudioChannel.
   if (winData->mChannels[(uint32_t)aChannel].mNumberOfAgents == 1) {
     NotifyChannelActive(aAgent->WindowID(), aChannel, true);
   }
 
   // If this is the first agent for this window, we must notify the observers.
-  if (aNotifyPlayback == nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY &&
-      winData->mAgents.Length() == 1) {
+  if (winData->mAgents.Length() == 1) {
     RefPtr<MediaPlaybackRunnable> runnable =
       new MediaPlaybackRunnable(aAgent->Window(), true /* active */);
     NS_DispatchToCurrentThread(runnable);
   }
 
+  // If the window has already been captured, the agent of that window should
+  // also be captured.
+  if (winData->mIsAudioCaptured) {
+    aAgent->WindowAudioCaptureChanged(aAgent->InnerWindowID(),
+                                      winData->mIsAudioCaptured);
+  }
+
   MaybeSendStatusUpdate();
 }
 
 void
-AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent,
-                                                 uint32_t aNotifyPlayback)
+AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
 {
   AudioChannelWindow* winData = GetWindowData(aAgent->WindowID());
   if (!winData) {
     return;
   }
 
   if (winData->mAgents.Contains(aAgent)) {
     int32_t channel = aAgent->AudioChannelType();
@@ -328,23 +332,27 @@ AudioChannelService::UnregisterAudioChan
 #ifdef MOZ_WIDGET_GONK
   bool active = AnyAudioChannelIsActive();
   for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
     mSpeakerManager[i]->SetAudioChannelActive(active);
   }
 #endif
 
   // If this is the last agent for this window, we must notify the observers.
-  if (aNotifyPlayback == nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY &&
-      winData->mAgents.IsEmpty()) {
+  if (winData->mAgents.IsEmpty()) {
     RefPtr<MediaPlaybackRunnable> runnable =
       new MediaPlaybackRunnable(aAgent->Window(), false /* active */);
     NS_DispatchToCurrentThread(runnable);
   }
 
+  // No need to capture non-audible object.
+  if (winData->mIsAudioCaptured) {
+    aAgent->WindowAudioCaptureChanged(aAgent->InnerWindowID(), false);
+  }
+
   MaybeSendStatusUpdate();
 }
 
 void
 AudioChannelService::RegisterTabParent(TabParent* aTabParent)
 {
   MOZ_ASSERT(aTabParent);
   MOZ_ASSERT(!mTabParents.Contains(aTabParent));
@@ -622,42 +630,51 @@ AudioChannelService::RefreshAgentsVolume
   nsTObserverArray<AudioChannelAgent*>::ForwardIterator
     iter(winData->mAgents);
   while (iter.HasMore()) {
     iter.GetNext()->WindowVolumeChanged();
   }
 }
 
 void
-AudioChannelService::RefreshAgentsCapture(nsPIDOMWindow* aWindow,
-                                          uint64_t aInnerWindowID)
+AudioChannelService::SetWindowAudioCaptured(nsPIDOMWindow* aWindow,
+                                            uint64_t aInnerWindowID,
+                                            bool aCapture)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsOuterWindow());
 
+  MOZ_LOG(GetAudioChannelLog(), LogLevel::Debug,
+         ("AudioChannelService, SetWindowAudioCaptured, window = %p, "
+          "aCapture = %d\n", aWindow, aCapture));
+
   nsCOMPtr<nsPIDOMWindow> topWindow = aWindow->GetScriptableTop();
   if (!topWindow) {
     return;
   }
 
   AudioChannelWindow* winData = GetWindowData(topWindow->WindowID());
 
   // This can happen, but only during shutdown, because the the outer window
   // changes ScriptableTop, so that its ID is different.
   // In this case either we are capturing, and it's too late because the window
   // has been closed anyways, or we are un-capturing, and everything has already
   // been cleaned up by the HTMLMediaElements or the AudioContexts.
   if (!winData) {
     return;
   }
 
-  nsTObserverArray<AudioChannelAgent*>::ForwardIterator
-    iter(winData->mAgents);
-  while (iter.HasMore()) {
-    iter.GetNext()->WindowAudioCaptureChanged(aInnerWindowID);
+  if (aCapture != winData->mIsAudioCaptured) {
+    winData->mIsAudioCaptured = aCapture;
+    nsTObserverArray<AudioChannelAgent*>::ForwardIterator
+      iter(winData->mAgents);
+    while (iter.HasMore()) {
+      iter.GetNext()->WindowAudioCaptureChanged(aInnerWindowID, aCapture);
+    }
   }
 }
 
 /* static */ const nsAttrValue::EnumTable*
 AudioChannelService::GetAudioChannelTable()
 {
   return kMozAudioChannelAttributeTable;
 }
@@ -785,17 +802,17 @@ AudioChannelService::SetAudioChannelVolu
                                            float aVolume)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsOuterWindow());
 
   MOZ_LOG(GetAudioChannelLog(), LogLevel::Debug,
          ("AudioChannelService, SetAudioChannelVolume, window = %p, type = %d, "
-          "volume = %d\n", aWindow, aAudioChannel, aVolume));
+          "volume = %f\n", aWindow, aAudioChannel, aVolume));
 
   AudioChannelWindow* winData = GetOrCreateWindowData(aWindow);
   winData->mChannels[(uint32_t)aAudioChannel].mVolume = aVolume;
   RefreshAgentsVolumeAndPropagate(aAudioChannel, aWindow);
 }
 
 NS_IMETHODIMP
 AudioChannelService::SetAudioChannelVolume(nsIDOMWindow* aWindow,
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -51,25 +51,23 @@ public:
 
   static PRLogModuleInfo* GetAudioChannelLog();
 
   /**
    * Any audio channel agent that starts playing should register itself to
    * this service, sharing the AudioChannel.
    */
   void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
-                                 uint32_t aNotifyPlayback,
                                  AudioChannel aChannel);
 
   /**
    * Any audio channel agent that stops playing should unregister itself to
    * this service.
    */
-  void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent,
-                                   uint32_t aNotifyPlayback);
+  void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
 
   /**
    * For nested iframes.
    */
   void RegisterTabParent(TabParent* aTabParent);
   void UnregisterTabParent(TabParent* aTabParent);
 
   /**
@@ -119,18 +117,19 @@ public:
 
   void RefreshAgentsVolumeAndPropagate(AudioChannel aAudioChannel,
                                        nsPIDOMWindow* aWindow);
 
   // This method needs to know the inner window that wants to capture audio. We
   // group agents per top outer window, but we can have multiple innerWindow per
   // top outerWindow (subiframes, etc.) and we have to identify all the agents
   // just for a particular innerWindow.
-  void RefreshAgentsCapture(nsPIDOMWindow* aWindow,
-                            uint64_t aInnerWindowID);
+  void SetWindowAudioCaptured(nsPIDOMWindow* aWindow,
+                              uint64_t aInnerWindowID,
+                              bool aCapture);
 
 
 #ifdef MOZ_WIDGET_GONK
   void RegisterSpeakerManager(SpeakerManagerService* aSpeakerManager)
   {
     if (!mSpeakerManager.Contains(aSpeakerManager)) {
       mSpeakerManager.AppendElement(aSpeakerManager);
     }
@@ -184,23 +183,25 @@ private:
     bool mMuted;
 
     uint32_t mNumberOfAgents;
   };
 
   struct AudioChannelWindow final
   {
     explicit AudioChannelWindow(uint64_t aWindowID)
-      : mWindowID(aWindowID)
+      : mWindowID(aWindowID),
+        mIsAudioCaptured(false)
     {
       // Workaround for bug1183033, system channel type can always playback.
       mChannels[(int16_t)AudioChannel::System].mMuted = false;
     }
 
     uint64_t mWindowID;
+    bool mIsAudioCaptured;
     AudioChannelConfig mChannels[NUMBER_OF_AUDIO_CHANNELS];
 
     // Raw pointer because the AudioChannelAgent must unregister itself.
     nsTObserverArray<AudioChannelAgent*> mAgents;
   };
 
   AudioChannelWindow*
   GetOrCreateWindowData(nsPIDOMWindow* aWindow);
--- a/dom/audiochannel/nsIAudioChannelAgent.idl
+++ b/dom/audiochannel/nsIAudioChannelAgent.idl
@@ -1,45 +1,45 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMWindow;
 
-[uuid(5fe83b24-38b9-4901-a4a1-d1bd57d3fe18)]
+[uuid(0a451ee0-972e-11e5-a837-0800200c9a66)]
 interface nsIAudioChannelAgentCallback : nsISupports
 {
   /**
    * Notified when the window volume/mute is changed
    */
   void windowVolumeChanged(in float aVolume, in bool aMuted);
 
   /**
    * Notified when the capture state is changed.
    */
-  void windowAudioCaptureChanged();
+  void windowAudioCaptureChanged(in bool aCapture);
 };
 
 /**
  * This interface provides an agent for gecko components to participate
  * in the audio channel service. Gecko components are responsible for
  *   1. Indicating what channel type they are using (via the init() member
  *      function).
  *   2. Before playing, checking the playable status of the channel.
  *   3. Notifying the agent when they start/stop using this channel.
  *   4. Notifying the agent of changes to the visibility of the component using
  *      this channel.
  *
  * The agent will invoke a callback to notify Gecko components of
  *   1. Changes to the playable status of this channel.
  */
 
-[uuid(18222148-1b32-463d-b050-b741f43a07ba)]
+[uuid(ab7e21c0-970c-11e5-a837-0800200c9a66)]
 interface nsIAudioChannelAgent : nsISupports
 {
   const long AUDIO_AGENT_CHANNEL_NORMAL             = 0;
   const long AUDIO_AGENT_CHANNEL_CONTENT            = 1;
   const long AUDIO_AGENT_CHANNEL_NOTIFICATION       = 2;
   const long AUDIO_AGENT_CHANNEL_ALARM              = 3;
   const long AUDIO_AGENT_CHANNEL_TELEPHONY          = 4;
   const long AUDIO_AGENT_CHANNEL_RINGER             = 5;
@@ -47,19 +47,16 @@ interface nsIAudioChannelAgent : nsISupp
   const long AUDIO_AGENT_CHANNEL_SYSTEM             = 7;
 
   const long AUDIO_AGENT_CHANNEL_ERROR              = 1000;
 
   const long AUDIO_AGENT_STATE_NORMAL               = 0;
   const long AUDIO_AGENT_STATE_MUTED                = 1;
   const long AUDIO_AGENT_STATE_FADED                = 2;
 
-  const long AUDIO_AGENT_DONT_NOTIFY                = 0;
-  const long AUDIO_AGENT_NOTIFY                     = 1;
-
   /**
    * Before init() is called, this returns AUDIO_AGENT_CHANNEL_ERROR.
    */
   readonly attribute long audioChannelType;
 
   %{C++
   inline int32_t AudioChannelType() {
     int32_t channel;
@@ -96,29 +93,25 @@ interface nsIAudioChannelAgent : nsISupp
   void initWithWeakCallback(in nsIDOMWindow window, in long channelType,
                             in nsIAudioChannelAgentCallback callback);
 
   /**
    * Notify the agent that we want to start playing.
    * Note: Gecko component SHOULD call this function first then start to
    *          play audio stream only when return value is true.
    *
-   * @param notifyPlaying
-   *   Whether to send audio-playback notifications, one of AUDIO_CHANNEL_NOTIFY
-   *   or AUDIO_CHANNEL_DONT_NOTIFY.
-   *
    * @return
    *    normal state: the agent has registered with audio channel service and
    *          the component should start playback.
    *    muted state: the agent has registered with audio channel service but
    *          the component should not start playback.
    *    faded state: the agent has registered with audio channel service the
    *          component should start playback as well as reducing the volume.
    */
-  void notifyStartedPlaying(in unsigned long notifyPlayback, out float volume, out bool muted);
+  void notifyStartedPlaying(out float volume, out bool muted);
 
   /**
    * Notify the agent we no longer want to play.
    *
    * Note : even if notifyStartedPlaying() returned false, the agent would
    * still be registered with the audio channel service and receive callbacks
    * for status changes. So notifyStoppedPlaying must still eventually be
    * called to unregister the agent with the channel service.
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3738,17 +3738,17 @@ nsresult
 nsPIDOMWindow::SetAudioCapture(bool aCapture)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   mAudioCaptured = aCapture;
 
   RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
   if (service) {
-    service->RefreshAgentsCapture(GetOuterWindow(), mWindowID);
+    service->SetWindowAudioCaptured(GetOuterWindow(), mWindowID, aCapture);
   }
 
   return NS_OK;
 }
 
 // nsISpeechSynthesisGetter
 
 #ifdef MOZ_WEBSPEECH
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -1182,18 +1182,17 @@ nsDOMCameraControl::NotifyRecordingStatu
       return NS_ERROR_UNEXPECTED;
     }
 
     // Camera app will stop recording when it falls to the background, so no callback is necessary.
     mAudioChannelAgent->Init(mWindow, (int32_t)AudioChannel::Content, nullptr);
     // Video recording doesn't output any sound, so it's not necessary to check canPlay.
     float volume = 0.0;
     bool muted = true;
-    rv = mAudioChannelAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_DONT_NOTIFY,
-                                                  &volume, &muted);
+    rv = mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 #endif
   return rv;
 }
 
--- a/dom/crypto/CryptoKey.cpp
+++ b/dom/crypto/CryptoKey.cpp
@@ -969,21 +969,26 @@ CryptoKey::PrivateKeyToJwk(SECKEYPrivate
 SECKEYPublicKey*
 CreateECPublicKey(const SECItem* aKeyData, const nsString& aNamedCurve)
 {
   ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
   if (!arena) {
     return nullptr;
   }
 
-  SECKEYPublicKey* key = PORT_ArenaZNew(arena, SECKEYPublicKey);
+  // It's important that this be a ScopedSECKEYPublicKey, as this ensures that
+  // SECKEY_DestroyPublicKey will be called on it. If this doesn't happen, when
+  // CryptoKey::PublicKeyValid is called on it and it gets moved to the internal
+  // PKCS#11 slot, it will leak a reference to the slot.
+  ScopedSECKEYPublicKey key(PORT_ArenaZNew(arena, SECKEYPublicKey));
   if (!key) {
     return nullptr;
   }
 
+  key->arena = nullptr; // key doesn't own the arena; it won't get double-freed
   key->keyType = ecKey;
   key->pkcs11Slot = nullptr;
   key->pkcs11ID = CK_INVALID_HANDLE;
 
   // Create curve parameters.
   SECItem* params = CreateECParamsForCurve(aNamedCurve, arena);
   if (!params) {
     return nullptr;
--- a/dom/fmradio/FMRadio.cpp
+++ b/dom/fmradio/FMRadio.cpp
@@ -449,33 +449,32 @@ FMRadio::DisableRDS()
 
 void
 FMRadio::EnableAudioChannelAgent()
 {
   NS_ENSURE_TRUE_VOID(mAudioChannelAgent);
 
   float volume = 0.0;
   bool muted = true;
-  mAudioChannelAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY,
-                                           &volume, &muted);
+  mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
   WindowVolumeChanged(volume, muted);
 
   mAudioChannelAgentEnabled = true;
 }
 
 NS_IMETHODIMP
 FMRadio::WindowVolumeChanged(float aVolume, bool aMuted)
 {
   IFMRadioService::Singleton()->EnableAudio(!aMuted);
   // TODO: what about the volume?
   return NS_OK;
 }
 
 NS_IMETHODIMP
-FMRadio::WindowAudioCaptureChanged()
+FMRadio::WindowAudioCaptureChanged(bool aCapture)
 {
   return NS_OK;
 }
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FMRadio)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -109,41 +109,28 @@ static mozilla::LazyLogModule gMediaElem
 #include "mozilla/EventStateManager.h"
 
 using namespace mozilla::layers;
 using mozilla::net::nsMediaFragmentURIParser;
 
 class MOZ_STACK_CLASS AutoNotifyAudioChannelAgent
 {
   RefPtr<mozilla::dom::HTMLMediaElement> mElement;
-  bool mShouldNotify;
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
 public:
-  AutoNotifyAudioChannelAgent(mozilla::dom::HTMLMediaElement* aElement,
-                              bool aNotify
-                              MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+  explicit AutoNotifyAudioChannelAgent(mozilla::dom::HTMLMediaElement* aElement
+                                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
     : mElement(aElement)
-    , mShouldNotify(aNotify)
   {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    if (mShouldNotify) {
-      // The audio channel agent may not exist now.
-      if (mElement->MaybeCreateAudioChannelAgent()) {
-        mElement->NotifyAudioChannelAgent(false);
-      }
-    }
-  }
+  }
+
   ~AutoNotifyAudioChannelAgent()
   {
-    if (mShouldNotify) {
-      // The audio channel agent is destroyed at this point.
-      if (mElement->MaybeCreateAudioChannelAgent()) {
-        mElement->NotifyAudioChannelAgent(true);
-      }
-    }
+    mElement->UpdateAudioChannelPlayingState();
   }
 };
 
 namespace mozilla {
 namespace dom {
 
 // Number of milliseconds between progress events as defined by spec
 static const uint32_t PROGRESS_MS = 350;
@@ -3394,20 +3381,17 @@ void HTMLMediaElement::ProcessMediaFragm
 void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
                                       nsAutoPtr<const MetadataTags> aTags)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // If the element is gaining or losing an audio track, we need to notify
   // the audio channel agent so that the correct audio-playback events will
   // get dispatched.
-  bool audioTrackChanging = mMediaInfo.HasAudio() != aInfo->HasAudio();
-  AutoNotifyAudioChannelAgent autoNotify(this,
-                                         audioTrackChanging &&
-                                         mPlayingThroughTheAudioChannel);
+  AutoNotifyAudioChannelAgent autoNotify(this);
 
   mMediaInfo = *aInfo;
   mIsEncrypted = aInfo->IsEncrypted()
 #ifdef MOZ_EME
                  || mPendingEncryptedInitData.IsEncrypted()
 #endif // MOZ_EME
                  ;
   mTags = aTags.forget();
@@ -4357,18 +4341,16 @@ void HTMLMediaElement::DoRemoveSelfRefer
   // We don't need the shutdown observer anymore. Unregistering releases
   // its reference to us, which we were using as our self-reference.
   nsContentUtils::UnregisterShutdownObserver(this);
 }
 
 nsresult HTMLMediaElement::Observe(nsISupports* aSubject,
                                    const char* aTopic, const char16_t* aData)
 {
-  NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
-
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
     mShuttingDown = true;
     AddRemoveSelfReference();
   }
   return NS_OK;
 }
 
 bool
@@ -4756,16 +4738,21 @@ HTMLMediaElement::MaybeCreateAudioChanne
 bool
 HTMLMediaElement::IsPlayingThroughTheAudioChannel() const
 {
   // Are we paused or muted
   if (mPaused || Muted()) {
     return false;
   }
 
+  // If this element doesn't have any audio tracks.
+  if (!HasAudio()) {
+    return false;
+  }
+
   // The volume should not be ~0
   if (std::fabs(Volume()) <= 1e-7) {
     return false;
   }
 
   // We should consider any bfcached page or inactive document as non-playing.
   if (!IsActive()) {
     return false;
@@ -4811,33 +4798,25 @@ HTMLMediaElement::UpdateAudioChannelPlay
       NotifyAudioChannelAgent(mPlayingThroughTheAudioChannel);
     }
   }
 }
 
 void
 HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying)
 {
-  // Immediately check if this should go to the MSG instead of the normal
-  // media playback route.
-  WindowAudioCaptureChanged();
-
   // This is needed to pass nsContentUtils::IsCallerChrome().
   // AudioChannel API should not called from content but it can happen that
   // this method has some content JS in its stack.
   AutoNoJSAPI nojsapi;
 
   if (aPlaying) {
-    // Don't notify playback if this element doesn't have any audio tracks.
-    uint32_t notify = HasAudio() ? nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY :
-                                   nsIAudioChannelAgent::AUDIO_AGENT_DONT_NOTIFY;
-
     float volume = 0.0;
     bool muted = true;
-    mAudioChannelAgent->NotifyStartedPlaying(notify, &volume, &muted);
+    mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
     WindowVolumeChanged(volume, muted);
   } else {
     mAudioChannelAgent->NotifyStoppedPlaying();
     mAudioChannelAgent = nullptr;
   }
 }
 
 NS_IMETHODIMP HTMLMediaElement::WindowVolumeChanged(float aVolume, bool aMuted)
@@ -4989,27 +4968,27 @@ HTMLMediaElement::GetTopLevelPrincipal()
   if (!doc) {
     return nullptr;
   }
   principal = doc->NodePrincipal();
   return principal.forget();
 }
 #endif // MOZ_EME
 
-NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
+NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged(bool aCapture)
 {
   MOZ_ASSERT(mAudioChannelAgent);
+  MOZ_ASSERT(HasAudio());
 
   if (!OwnerDoc()->GetInnerWindow()) {
     return NS_OK;
   }
-  bool captured = OwnerDoc()->GetInnerWindow()->GetAudioCaptured();
-
-  if (captured != mAudioCapturedByWindow) {
-    if (captured) {
+
+  if (aCapture != mAudioCapturedByWindow) {
+    if (aCapture) {
       mAudioCapturedByWindow = true;
       nsCOMPtr<nsPIDOMWindow> window =
         do_QueryInterface(OwnerDoc()->GetParentObject());
       uint64_t id = window->WindowID();
       MediaStreamGraph* msg =
         MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
                                       mAudioChannel);
 
@@ -5035,17 +5014,17 @@ NS_IMETHODIMP HTMLMediaElement::WindowAu
 
         mDecoder->RemoveOutputStream(ps);
       }
       mCaptureStreamPort->Destroy();
       mCaptureStreamPort = nullptr;
     }
   }
 
-   return NS_OK;
+  return NS_OK;
 }
 
 AudioTrackList*
 HTMLMediaElement::AudioTracks()
 {
   if (!mAudioTrackList) {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(OwnerDoc()->GetParentObject());
     mAudioTrackList = new AudioTrackList(window, this);
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -532,41 +532,39 @@ AudioDestinationNode::WindowVolumeChange
     }
   }
 
   SetCanPlay(aVolume, aMuted);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-AudioDestinationNode::WindowAudioCaptureChanged()
+AudioDestinationNode::WindowAudioCaptureChanged(bool aCapture)
 {
   MOZ_ASSERT(mAudioChannelAgent);
 
   if (!mStream || Context()->IsOffline()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindow> ownerWindow = GetOwner();
   if (!ownerWindow) {
     return NS_OK;
   }
 
-  bool captured = ownerWindow->GetAudioCaptured();
-
-  if (captured != mCaptured) {
-    if (captured) {
+  if (aCapture != mCaptured) {
+    if (aCapture) {
       nsCOMPtr<nsPIDOMWindow> window = Context()->GetParentObject();
       uint64_t id = window->WindowID();
       mCaptureStreamPort =
         mStream->Graph()->ConnectToCaptureStream(id, mStream);
     } else {
       mCaptureStreamPort->Destroy();
     }
-    mCaptured = captured;
+    mCaptured = aCapture;
   }
 
   return NS_OK;
 }
 
 AudioChannel
 AudioDestinationNode::MozAudioChannelType() const
 {
@@ -648,20 +646,17 @@ AudioDestinationNode::CreateAudioChannel
   mAudioChannelAgent = new AudioChannelAgent();
   rv = mAudioChannelAgent->InitWithWeakCallback(GetOwner(),
                                            static_cast<int32_t>(mAudioChannel),
                                            this);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = WindowAudioCaptureChanged();
-  NS_WARN_IF(NS_FAILED(rv));
-  return rv;
-
+  return NS_OK;
 }
 
 void
 AudioDestinationNode::NotifyStableState()
 {
   mExtraCurrentTimeUpdatedSinceLastStableState = false;
 }
 
@@ -741,20 +736,18 @@ AudioDestinationNode::InputMuted(bool aM
 
   if (aMuted) {
     mAudioChannelAgent->NotifyStoppedPlaying();
     return;
   }
 
   float volume = 0.0;
   bool muted = true;
-  nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY,
-                                                         &volume, &muted);
+  nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  WindowAudioCaptureChanged();
   WindowVolumeChanged(volume, muted);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -691,17 +691,17 @@ nsSpeechTask::CreateAudioChannelAgent()
   }
 
   mAudioChannelAgent = new AudioChannelAgent();
   mAudioChannelAgent->InitWithWeakCallback(mUtterance->GetOwner(),
                                            static_cast<int32_t>(AudioChannelService::GetDefaultAudioChannel()),
                                            this);
   float volume = 0.0f;
   bool muted = true;
-  mAudioChannelAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY, &volume, &muted);
+  mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
 }
 
 void
 nsSpeechTask::DestroyAudioChannelAgent()
 {
   if (mAudioChannelAgent) {
     mAudioChannelAgent->NotifyStoppedPlaying();
     mAudioChannelAgent = nullptr;
@@ -711,17 +711,17 @@ nsSpeechTask::DestroyAudioChannelAgent()
 NS_IMETHODIMP
 nsSpeechTask::WindowVolumeChanged(float aVolume, bool aMuted)
 {
   SetAudioOutputVolume(aMuted ? 0.0 : mVolume * aVolume);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSpeechTask::WindowAudioCaptureChanged()
+nsSpeechTask::WindowAudioCaptureChanged(bool aCapture)
 {
   // This is not supported yet.
   return NS_OK;
 }
 
 void
 nsSpeechTask::SetAudioOutputVolume(float aVolume)
 {
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2291,18 +2291,17 @@ NPError
       if (isMuted) {
         rv = agent->NotifyStoppedPlaying();
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return NPERR_NO_ERROR;
         }
       } else {
         float volume = 0.0;
         bool muted = true;
-        rv = agent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY,
-                                         &volume, &muted);
+        rv = agent->NotifyStartedPlaying(&volume, &muted);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return NPERR_NO_ERROR;
         }
 
         rv = inst->WindowVolumeChanged(volume, muted);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return NPERR_NO_ERROR;
         }
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -1855,17 +1855,17 @@ nsNPAPIPluginInstance::WindowVolumeChang
 {
   // We just support mute/unmute
   nsresult rv = SetMuted(aMuted);
   NS_WARN_IF(NS_FAILED(rv));
   return rv;
 }
 
 NS_IMETHODIMP
-nsNPAPIPluginInstance::WindowAudioCaptureChanged()
+nsNPAPIPluginInstance::WindowAudioCaptureChanged(bool aCapture)
 {
   return NS_OK;
 }
 
 nsresult
 nsNPAPIPluginInstance::SetMuted(bool aIsMuted)
 {
   if (RUNNING != mRunning)
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -557,18 +557,17 @@ Telephony::HandleAudioAgentState()
     mAudioAgent = nullptr;
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else if (!activeCall.IsNull() && !mIsAudioStartPlaying) {
     mIsAudioStartPlaying = true;
     float volume;
     bool muted;
-    rv = mAudioAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY,
-                                           &volume, &muted);
+    rv = mAudioAgent->NotifyStartedPlaying(&volume, &muted);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     // In B2G, the system app manages audio playback policy. If there is a new
     // sound want to be playback, it must wait for the permission from the
     // system app. It means that the sound would be muted first, and then be
     // unmuted. For telephony, the behaviors are hold() first, then resume().
@@ -707,17 +706,17 @@ Telephony::WindowVolumeChanged(float aVo
       mHaveDispatchedInterruptBeginEvent = mMuted;
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-Telephony::WindowAudioCaptureChanged()
+Telephony::WindowAudioCaptureChanged(bool aCapture)
 {
   // Do nothing, it's useless for the telephony object.
   return NS_OK;
 }
 
 // nsITelephonyListener
 
 NS_IMETHODIMP
--- a/gfx/2d/FilterNodeD2D1.cpp
+++ b/gfx/2d/FilterNodeD2D1.cpp
@@ -570,16 +570,20 @@ FilterNodeD2D1::Create(ID2D1DeviceContex
 
   hr = aDC->CreateEffect(GetCLDIDForFilterType(aType), getter_AddRefs(effect));
 
   if (FAILED(hr) || !effect) {
     gfxCriticalErrorOnce() << "Failed to create effect for FilterType: " << hexa(hr);
     return nullptr;
   }
 
+  if (aType == FilterType::ARITHMETIC_COMBINE) {
+    effect->SetValue(D2D1_ARITHMETICCOMPOSITE_PROP_CLAMP_OUTPUT, TRUE);
+  }
+
   RefPtr<FilterNodeD2D1> filter = new FilterNodeD2D1(effect, aType);
 
   if (HasUnboundedOutputRegion(aType)) {
     // These filters can produce non-transparent output from transparent
     // input pixels, and we want them to have an unbounded output region.
     filter = new FilterNodeExtendInputAdapterD2D1(aDC, filter, aType);
   }
 
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -43,16 +43,17 @@
 
 #include "cairo.h"
 
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 #include "graphite2/Font.h"
 
 #include <algorithm>
+#include <limits>
 #include <cmath>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::unicode;
 using mozilla::services::GetObserverService;
 
 gfxFontCache *gfxFontCache::gGlobalCache = nullptr;
@@ -1854,32 +1855,32 @@ gfxFont::DrawGlyphs(gfxShapedText       
 void
 gfxFont::DrawEmphasisMarks(gfxTextRun* aShapedText, gfxPoint* aPt,
                            uint32_t aOffset, uint32_t aCount,
                            const EmphasisMarkDrawParams& aParams)
 {
     gfxFloat& inlineCoord = aParams.isVertical ? aPt->y : aPt->x;
     uint32_t markLength = aParams.mark->GetLength();
 
-    gfxFloat clusterStart = NAN;
+    gfxFloat clusterStart = -std::numeric_limits<gfxFloat>::infinity();
     bool shouldDrawEmphasisMark = false;
     for (uint32_t i = 0, idx = aOffset; i < aCount; ++i, ++idx) {
         if (aParams.spacing) {
             inlineCoord += aParams.direction * aParams.spacing[i].mBefore;
         }
-        if (aShapedText->IsClusterStart(idx)) {
+        if (aShapedText->IsClusterStart(idx) ||
+            clusterStart == -std::numeric_limits<gfxFloat>::infinity()) {
             clusterStart = inlineCoord;
         }
         if (aShapedText->CharMayHaveEmphasisMark(idx)) {
             shouldDrawEmphasisMark = true;
         }
         inlineCoord += aParams.direction * aShapedText->GetAdvanceForGlyph(idx);
         if (shouldDrawEmphasisMark &&
             (i + 1 == aCount || aShapedText->IsClusterStart(idx + 1))) {
-            MOZ_ASSERT(!std::isnan(clusterStart), "Should have cluster start");
             gfxFloat clusterAdvance = inlineCoord - clusterStart;
             // Move the coord backward to get the needed start point.
             gfxFloat delta = (clusterAdvance + aParams.advance) / 2;
             inlineCoord -= delta;
             aParams.mark->Draw(aParams.context, *aPt, DrawMode::GLYPH_FILL,
                                0, markLength, nullptr, nullptr, nullptr);
             inlineCoord += delta;
             shouldDrawEmphasisMark = false;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -2103,16 +2103,28 @@ DumpObject(JSContext* cx, unsigned argc,
 
     DumpObject(obj);
 
     args.rval().setUndefined();
     return true;
 }
 #endif
 
+static bool
+SharedMemoryEnabled(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+#ifdef ENABLE_SHARED_ARRAY_BUFFER
+    args.rval().setBoolean(true);
+#else
+    args.rval().setBoolean(false);
+#endif
+    return true;
+}
+
 #ifdef NIGHTLY_BUILD
 static bool
 ObjectAddress(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
         RootedObject callee(cx, &args.callee());
         ReportUsageError(cx, callee, "Wrong number of arguments");
@@ -3503,16 +3515,20 @@ gc::ZealModeHelpText),
 "  the last array element is implicitly |target|.\n"),
 
 #ifdef DEBUG
     JS_FN_HELP("dumpObject", DumpObject, 1, 0,
 "dumpObject()",
 "  Dump an internal representation of an object."),
 #endif
 
+    JS_FN_HELP("sharedMemoryEnabled", SharedMemoryEnabled, 0, 0,
+"sharedMemoryEnabled()",
+"  Return true if SharedArrayBuffer and Atomics are enabled"),
+
 #ifdef NIGHTLY_BUILD
     JS_FN_HELP("objectAddress", ObjectAddress, 1, 0,
 "objectAddress(obj)",
 "  Return the current address of the object. For debugging only--this\n"
 "  address may change during a moving GC."),
 
     JS_FN_HELP("sharedAddress", SharedAddress, 1, 0,
 "sharedAddress(obj)",
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -352,48 +352,32 @@ BytecodeEmitter::emitDupAt(unsigned slot
     if (!emitN(JSOP_DUPAT, 3, &off))
         return false;
 
     jsbytecode* pc = code(off);
     SET_UINT24(pc, slotFromTop);
     return true;
 }
 
-/* XXX too many "... statement" L10N gaffes below -- fix via js.msg! */
-const char js_with_statement_str[] = "with statement";
-const char js_finally_block_str[]  = "finally block";
-
-static const char * const statementName[] = {
-    "label statement",       /* LABEL */
-    "if statement",          /* IF */
-    "else statement",        /* ELSE */
-    "destructuring body",    /* BODY */
-    "switch statement",      /* SWITCH */
-    "block",                 /* BLOCK */
-    js_with_statement_str,   /* WITH */
-    "catch block",           /* CATCH */
-    "try block",             /* TRY */
-    js_finally_block_str,    /* FINALLY */
-    js_finally_block_str,    /* SUBROUTINE */
-    "do loop",               /* DO_LOOP */
-    "for loop",              /* FOR_LOOP */
-    "for/in loop",           /* FOR_IN_LOOP */
-    "for/of loop",           /* FOR_OF_LOOP */
-    "while loop",            /* WHILE_LOOP */
-    "spread",                /* SPREAD */
-};
-
-static_assert(MOZ_ARRAY_LENGTH(statementName) == uint16_t(StmtType::LIMIT),
-              "statementName array and StmtType enum must be consistent");
-
 static const char*
 StatementName(StmtInfoBCE* stmt)
 {
     if (!stmt)
         return js_script_str;
+
+    /* XXX too many "... statement" L10N gaffes -- fix via js.msg! */
+    static const char* const statementName[] = {
+    #define STATEMENT_TYPE_NAME(name, desc) desc,
+        FOR_EACH_STATEMENT_TYPE(STATEMENT_TYPE_NAME)
+    #undef STATEMENT_TYPE_NAME
+    };
+
+    static_assert(MOZ_ARRAY_LENGTH(statementName) == uint16_t(StmtType::LIMIT),
+                  "statementName array and StmtType enum must be consistent");
+
     return statementName[uint16_t(stmt->type)];
 }
 
 static void
 ReportStatementTooLarge(TokenStream& ts, StmtInfoBCE* stmt)
 {
     ts.reportError(JSMSG_NEED_DIET, StatementName(stmt));
 }
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -589,23 +589,36 @@ class FullParseHandler
         BinaryNode* pn = new_<BinaryNode>(PNK_COMPREHENSIONFOR, op,
                                           TokenPos(begin, body->pn_pos.end), forHead, body);
         if (!pn)
             return null();
         pn->pn_iflags = JSOP_ITER;
         return pn;
     }
 
+    ParseNode* newComprehensionBinding(ParseNode* kid) {
+        MOZ_ASSERT(kid->isKind(PNK_NAME));
+        return new_<ListNode>(PNK_LET, JSOP_NOP, kid);
+    }
+
     ParseNode* newForHead(ParseNodeKind kind, ParseNode* pn1, ParseNode* pn2, ParseNode* pn3,
                           const TokenPos& pos)
     {
         MOZ_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF || kind == PNK_FORHEAD);
         return new_<TernaryNode>(kind, JSOP_NOP, pn1, pn2, pn3, pos);
     }
 
+    void initForLetBlock(ParseNode* forLetImpliedBlock, ParseNode* nestedForLoop) {
+        MOZ_ASSERT(forLetImpliedBlock->isKind(PNK_LEXICALSCOPE));
+        MOZ_ASSERT(nestedForLoop->isKind(PNK_FOR));
+
+        forLetImpliedBlock->pn_expr = nestedForLoop;
+        forLetImpliedBlock->pn_pos = nestedForLoop->pn_pos;
+    }
+
     ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
         TokenPos pos(begin, caseList->pn_pos.end);
         return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);
     }
 
     ParseNode* newCaseOrDefault(uint32_t begin, ParseNode* expr, ParseNode* body) {
         return new_<CaseClause>(expr, body, begin);
     }
@@ -769,36 +782,68 @@ class FullParseHandler
 
     void setPosition(ParseNode* pn, const TokenPos& pos) {
         pn->pn_pos = pos;
     }
     TokenPos getPosition(ParseNode* pn) {
         return pn->pn_pos;
     }
 
+    bool isDeclarationKind(ParseNodeKind kind) {
+        return kind == PNK_VAR || kind == PNK_LET || kind == PNK_CONST;
+    }
+
     ParseNode* newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
-        MOZ_ASSERT(kind != PNK_VAR);
+        MOZ_ASSERT(!isDeclarationKind(kind));
         return new_<ListNode>(kind, op, pos());
     }
+
     ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
+        MOZ_ASSERT(!isDeclarationKind(kind));
         return new_<ListNode>(kind, op, TokenPos(begin, begin + 1));
     }
+
+    ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
+        MOZ_ASSERT(!isDeclarationKind(kind));
+        return new_<ListNode>(kind, op, kid);
+    }
+
     ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
-        MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
+        MOZ_ASSERT(isDeclarationKind(kind));
         return new_<ListNode>(kind, op, pos());
     }
 
-    /* New list with one initial child node. kid must be non-null. */
-    ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
-        MOZ_ASSERT(kind != PNK_VAR);
+    ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
+        MOZ_ASSERT(isDeclarationKind(kind));
         return new_<ListNode>(kind, op, kid);
     }
-    ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
-        MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
-        return new_<ListNode>(kind, op, kid);
+
+    bool isDeclarationList(ParseNode* node) {
+        return isDeclarationKind(node->getKind());
+    }
+
+    bool declarationIsVar(ParseNode* node) {
+        MOZ_ASSERT(isDeclarationList(node));
+        return node->isKind(PNK_VAR);
+    }
+
+    bool declarationIsLet(ParseNode* node) {
+        MOZ_ASSERT(isDeclarationList(node));
+        return node->isKind(PNK_LET);
+    }
+
+    bool declarationIsConst(ParseNode* node) {
+        MOZ_ASSERT(isDeclarationList(node));
+        return node->isKind(PNK_CONST);
+    }
+
+    ParseNode* singleBindingFromDeclaration(ParseNode* decl) {
+        MOZ_ASSERT(isDeclarationList(decl));
+        MOZ_ASSERT(decl->pn_count == 1);
+        return decl->pn_head;
     }
 
     ParseNode* newCatchList() {
         return new_<ListNode>(PNK_CATCHLIST, JSOP_NOP, pos());
     }
 
     ParseNode* newCommaExpressionList(ParseNode* kid) {
         return newList(PNK_COMMA, kid, JSOP_NOP);
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -770,20 +770,16 @@ Parser<FullParseHandler>::cloneParseTree
         pn->pn_u = opn->pn_u;
         break;
 
 #undef NULLCHECK
     }
     return pn;
 }
 
-template <>
-ParseNode*
-Parser<FullParseHandler>::cloneLeftHandSide(ParseNode* opn);
-
 /*
  * Used by Parser::cloneLeftHandSide to clone a default expression
  * in the form of
  *    [a = default] or {a: b = default}
  */
 template <>
 ParseNode*
 Parser<FullParseHandler>::cloneDestructuringDefault(ParseNode* opn)
@@ -886,16 +882,26 @@ Parser<FullParseHandler>::cloneLeftHandS
             pn->setDefn(false);
 
             handler.linkUseToDef(pn, (Definition*) opn);
         }
     }
     return pn;
 }
 
+template <>
+SyntaxParseHandler::Node
+Parser<SyntaxParseHandler>::cloneLeftHandSide(Node node)
+{
+    // See the comment in SyntaxParseHandler::singleBindingFromDeclaration for
+    // why this is okay.
+    MOZ_ASSERT(node == SyntaxParseHandler::NodeUnparenthesizedName);
+    return SyntaxParseHandler::NodeGeneric;
+}
+
 } /* namespace frontend */
 } /* namespace js */
 
 #ifdef DEBUG
 
 static const char * const parseNodeNames[] = {
 #define STRINGIFY(name) #name,
     FOR_EACH_PARSE_NODE_KIND(STRINGIFY)
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1516,16 +1516,25 @@ struct BindData
         return isConst_;
     }
 
     bool isAnnexB() {
         MOZ_ASSERT(isInitialized());
         return isAnnexB_;
     }
 
+    // The BoundNames of LexicalDeclaration and ForDeclaration must not contain
+    // 'let'.  (CatchParameter is the only lexical binding form without this
+    // restriction.)
+    bool mustNotBindLet() {
+        MOZ_ASSERT(isInitialized());
+        return isConst_ ||
+               (kind_ == LexicalBinding && letData_.overflow != JSMSG_TOO_MANY_CATCH_VARS);
+    }
+
     const LetData& letData() {
         MOZ_ASSERT(kind_ == LexicalBinding);
         return letData_;
     }
 
     bool bind(HandlePropertyName name, Parser<ParseHandler>* parser) {
         MOZ_ASSERT(isInitialized());
         MOZ_ASSERT(nameNode_ != ParseHandler::null());
@@ -3547,16 +3556,23 @@ Parser<FullParseHandler>::bindLexical(Bi
                                       HandlePropertyName name, Parser<FullParseHandler>* parser)
 {
     ParseContext<FullParseHandler>* pc = parser->pc;
     ParseNode* pn = data->nameNode();
     if (!parser->checkStrictBinding(name, pn))
         return false;
 
     ExclusiveContext* cx = parser->context;
+
+    // Most lexical declaration patterns can't bind the name 'let'.
+    if (data->mustNotBindLet() && name == cx->names().let) {
+        parser->report(ParseError, false, pn, JSMSG_LEXICAL_DECL_DEFINES_LET);
+        return false;
+    }
+
     Rooted<StaticBlockObject*> blockObj(cx, data->letData().blockObj);
 
     uint32_t index = StaticBlockObject::LOCAL_INDEX_LIMIT;
     if (blockObj) {
         // Leave the scope coordinate free on global lexicals.
         //
         // For block-level lets, assign block-local index to pn->pn_scopecoord
         // right away. The emitter will adjust the node's slot based on its
@@ -4351,231 +4367,359 @@ Parser<ParseHandler>::newBindingNode(Pro
             }
         }
     }
 
     /* Make a new node for this declarator name (or destructuring pattern). */
     return newName(name);
 }
 
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::expressionAfterForInOrOf(ParseNodeKind forHeadKind,
+                                               YieldHandling yieldHandling)
+{
+    MOZ_ASSERT(forHeadKind == PNK_FORIN || forHeadKind == PNK_FOROF);
+
+    return forHeadKind == PNK_FOROF
+           ? assignExpr(InAllowed, yieldHandling, TripledotProhibited)
+           : expr(InAllowed, yieldHandling, TripledotProhibited);
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::declarationPattern(Node decl, TokenKind tt, BindData<ParseHandler>* data,
+                                         bool initialDeclaration, YieldHandling yieldHandling,
+                                         ParseNodeKind* forHeadKind,
+                                         Node* forInOrOfExpression)
+{
+    MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LB) ||
+               tokenStream.isCurrentTokenType(TOK_LC));
+
+    Node pattern;
+    {
+        pc->inDeclDestructuring = true;
+        pattern = primaryExpr(yieldHandling, TripledotProhibited, tt);
+        pc->inDeclDestructuring = false;
+    }
+    if (!pattern)
+        return null();
+
+    if (initialDeclaration && forHeadKind) {
+        bool isForIn, isForOf;
+        if (!matchInOrOf(&isForIn, &isForOf))
+            return null();
+
+        if (isForIn)
+            *forHeadKind = PNK_FORIN;
+        else if (isForOf)
+            *forHeadKind = PNK_FOROF;
+        else
+            *forHeadKind = PNK_FORHEAD;
+
+        if (*forHeadKind != PNK_FORHEAD) {
+            // |for (const ... in ...);| and |for (const ... of ...);| are
+            // syntax errors for now.  We'll fix this in bug 449811.
+            if (handler.declarationIsConst(decl)) {
+                report(ParseError, false, pattern, JSMSG_BAD_CONST_DECL);
+                return null();
+            }
+
+            if (!checkDestructuringPattern(data, pattern))
+                return null();
+
+            *forInOrOfExpression = expressionAfterForInOrOf(*forHeadKind, yieldHandling);
+            if (!*forInOrOfExpression)
+                return null();
+
+            return pattern;
+        }
+    }
+
+    // See comment below for bindBeforeInitializer in the code that
+    // handles the non-destructuring case.
+    bool bindBeforeInitializer = handler.declarationIsVar(decl);
+    if (bindBeforeInitializer) {
+        if (!checkDestructuringPattern(data, pattern))
+            return null();
+    }
+
+    MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
+
+    Node init = assignExpr(forHeadKind ? InProhibited : InAllowed,
+                           yieldHandling, TripledotProhibited);
+    if (!init)
+        return null();
+
+    if (forHeadKind) {
+        // For for(;;) declarations, consistency with |for (;| parsing requires
+        // that the ';' first be examined as Operand, even though absence of a
+        // binary operator (examined with modifier None) terminated |init|.
+        // For all other declarations, through ASI's infinite majesty, a next
+        // token on a new line would begin an expression.
+        tokenStream.addModifierException(TokenStream::OperandIsNone);
+    }
+
+    if (!bindBeforeInitializer) {
+        if (!checkDestructuringPattern(data, pattern))
+            return null();
+    }
+
+    return handler.newBinary(PNK_ASSIGN, pattern, init);
+}
+
+template <typename ParseHandler>
+bool
+Parser<ParseHandler>::initializerInNameDeclaration(Node decl, Node binding,
+                                                   Handle<PropertyName*> name,
+                                                   BindData<ParseHandler>* data,
+                                                   bool initialDeclaration,
+                                                   YieldHandling yieldHandling,
+                                                   ParseNodeKind* forHeadKind,
+                                                   Node* forInOrOfExpression)
+{
+    MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN));
+
+    // Lexical bindings can't be accessed until initialized.  A declaration
+    // of the form |let x = x| raises a ReferenceError, as the 'x' on the
+    // RHS accesses the binding before it's initialized.
+    //
+    // If we're not parsing a lexical declaration, bind the name now.
+    // Otherwise we must wait until after parsing the initializing
+    // assignment.
+    bool bindBeforeInitializer = handler.declarationIsVar(decl);
+    if (bindBeforeInitializer) {
+        if (!data->bind(name, this))
+            return false;
+    }
+
+    Node initializer = assignExpr(forHeadKind ? InProhibited : InAllowed,
+                                  yieldHandling, TripledotProhibited);
+    if (!initializer)
+        return false;
+
+    bool performAssignment = true;
+    if (forHeadKind) {
+        if (initialDeclaration) {
+            bool isForIn, isForOf;
+            if (!matchInOrOf(&isForIn, &isForOf))
+                return false;
+
+            // An initialized declaration can't appear in a for-of:
+            //
+            //   for (var/let/const x = ... of ...); // BAD
+            if (isForOf) {
+                report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE);
+                return false;
+            }
+
+            if (isForIn) {
+                // Lexical declarations in for-in loops can't be initialized:
+                //
+                //   for (let/const x = ... in ...); // BAD
+                if (!handler.declarationIsVar(decl)) {
+                    report(ParseError, false, binding, JSMSG_BAD_FOR_LEFTSIDE);
+                    return false;
+                }
+
+                // This leaves only initialized for-in |var| declarations.  ES6
+                // forbids these, yet they sadly still occur, rarely, on the
+                // web.  *Don't* assign, and warn about this invalid syntax to
+                // incrementally move to ES6 semantics.
+                *forHeadKind = PNK_FORIN;
+                performAssignment = false;
+                if (!report(ParseWarning, pc->sc->strict(), initializer,
+                            JSMSG_INVALID_FOR_IN_DECL_WITH_INIT))
+                {
+                    return false;
+                }
+
+                *forInOrOfExpression = expressionAfterForInOrOf(PNK_FORIN, yieldHandling);
+                if (!*forInOrOfExpression)
+                    return null();
+            } else {
+                *forHeadKind = PNK_FORHEAD;
+            }
+        }
+
+        if (*forHeadKind == PNK_FORHEAD) {
+            // Per Parser::forHeadStart, the semicolon in |for (;| is
+            // ultimately gotten as Operand.  But initializer expressions
+            // terminate with the absence of an operator gotten as None, so we
+            // need an exception.
+            tokenStream.addModifierException(TokenStream::OperandIsNone);
+        }
+    }
+
+    if (performAssignment) {
+        if (!bindBeforeInitializer && !data->bind(name, this))
+            return false;
+
+        if (!handler.finishInitializerAssignment(binding, initializer))
+            return false;
+    }
+
+    return true;
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::declarationName(Node decl, TokenKind tt, BindData<ParseHandler>* data,
+                                      bool initialDeclaration, YieldHandling yieldHandling,
+                                      ParseNodeKind* forHeadKind, Node* forInOrOfExpression)
+{
+    if (tt != TOK_NAME) {
+        // Anything other than TOK_YIELD or TOK_NAME is an error.
+        if (tt != TOK_YIELD) {
+            report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME);
+            return null();
+        }
+
+        // TOK_YIELD is only okay if it's treated as a name.
+        if (!checkYieldNameValidity())
+            return null();
+    }
+
+    RootedPropertyName name(context, tokenStream.currentName());
+    Node binding = newBindingNode(name, handler.declarationIsVar(decl), HoistVars);
+    if (!binding)
+        return null();
+    MOZ_ASSERT(data->isConst() == handler.declarationIsConst(decl));
+    if (data->isConst())
+        handler.setFlag(binding, PND_CONST);
+    data->setNameNode(binding);
+
+    // The '=' context after a variable name in a declaration is an opportunity
+    // for ASI, and thus for the next token to start an ExpressionStatement:
+    //
+    //  var foo   // VariableDeclaration
+    //  /bar/g;   // ExpressionStatement
+    //
+    // Therefore get the token here as Operand.
+    bool matched;
+    if (!tokenStream.matchToken(&matched, TOK_ASSIGN, TokenStream::Operand))
+        return null();
+
+    if (matched) {
+        if (!initializerInNameDeclaration(decl, binding, name, data, initialDeclaration,
+                                          yieldHandling, forHeadKind, forInOrOfExpression))
+        {
+            return null();
+        }
+    } else {
+        tokenStream.addModifierException(TokenStream::NoneIsOperand);
+
+        bool constRequiringInitializer = handler.declarationIsConst(decl);
+        if (initialDeclaration && forHeadKind) {
+            bool isForIn, isForOf;
+            if (!matchInOrOf(&isForIn, &isForOf))
+                return null();
+
+            if (isForIn || isForOf) {
+                // XXX Uncomment this when fixing bug 449811.  Until then,
+                //     |for (const ... in/of ...)| remains an error.
+                //constRequiringInitializer = false;
+
+                *forHeadKind = isForIn ? PNK_FORIN : PNK_FOROF;
+            } else {
+                *forHeadKind = PNK_FORHEAD;
+            }
+        }
+
+        if (constRequiringInitializer) {
+            report(ParseError, false, binding, JSMSG_BAD_CONST_DECL);
+            return null();
+        }
+
+        bool bindBeforeInitializer = handler.declarationIsVar(decl);
+        if (bindBeforeInitializer) {
+            if (!data->bind(name, this))
+                return null();
+        }
+
+        if (forHeadKind && *forHeadKind != PNK_FORHEAD) {
+            *forInOrOfExpression = expressionAfterForInOrOf(*forHeadKind, yieldHandling);
+            if (!*forInOrOfExpression)
+                return null();
+        }
+
+        if (!bindBeforeInitializer) {
+            if (!data->bind(name, this))
+                return null();
+        }
+    }
+
+    handler.setLexicalDeclarationOp(binding, data->op());
+    return binding;
+}
+
 /*
  * The 'blockObj' parameter is non-null when parsing the 'vars' in a let
  * expression, block statement, non-top-level let declaration in statement
  * context, and the let-initializer of a for-statement.
  */
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::variables(YieldHandling yieldHandling,
-                                ParseNodeKind kind,
-                                ForInitLocation location,
-                                bool* psimple, StaticBlockObject* blockObj, VarContext varContext)
-{
-    MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
-
-    /*
-     * The simple flag is set if the declaration has the form 'var x', with
-     * only one variable declared and no initializer expression.
-     */
-    MOZ_ASSERT_IF(psimple, *psimple);
+Parser<ParseHandler>::declarationList(YieldHandling yieldHandling,
+                                      ParseNodeKind kind,
+                                      StaticBlockObject* blockObj /* = nullptr */,
+                                      ParseNodeKind* forHeadKind /* = nullptr */,
+                                      Node* forInOrOfExpression /* = nullptr */)
+{
+    MOZ_ASSERT(kind == PNK_VAR || kind == PNK_LET || kind == PNK_CONST);
+    MOZ_ASSERT_IF(blockObj != nullptr, kind == PNK_LET || kind == PNK_CONST);
 
     JSOp op;
     switch (kind) {
       case PNK_VAR:   op = JSOP_DEFVAR;   break;
       case PNK_CONST: op = JSOP_DEFCONST; break;
       case PNK_LET:   op = JSOP_DEFLET;   break;
       default: MOZ_CRASH("unknown variable kind");
     }
 
-    Node pn = handler.newDeclarationList(kind, op);
-    if (!pn)
+    Node decl = handler.newDeclarationList(kind, op);
+    if (!decl)
         return null();
 
     BindData<ParseHandler> data(context);
     if (kind == PNK_VAR)
         data.initVar(op);
     else
-        data.initLexical(varContext, op, blockObj, JSMSG_TOO_MANY_LOCALS);
-
-    bool first = true;
-    Node pn2;
-    while (true) {
-        do {
-            if (psimple && !first)
-                *psimple = false;
-            first = false;
-
-            TokenKind tt;
-            if (!tokenStream.getToken(&tt))
-                return null();
-            if (tt == TOK_LB || tt == TOK_LC) {
-                if (psimple)
-                    *psimple = false;
-
-                pc->inDeclDestructuring = true;
-                pn2 = primaryExpr(yieldHandling, TripledotProhibited, tt);
-                pc->inDeclDestructuring = false;
-                if (!pn2)
-                    return null();
-
-                bool parsingForInOrOfInit = false;
-                if (location == InForInit) {
-                    bool isForIn, isForOf;
-                    if (!matchInOrOf(&isForIn, &isForOf))
-                        return null();
-                    parsingForInOrOfInit = isForIn || isForOf;
-                }
-
-                // See comment below for bindBeforeInitializer in the code that
-                // handles the non-destructuring case.
-                bool bindBeforeInitializer = (kind != PNK_LET && kind != PNK_CONST) ||
-                                             parsingForInOrOfInit;
-                if (bindBeforeInitializer && !checkDestructuringPattern(&data, pn2))
-                    return null();
-
-                if (parsingForInOrOfInit) {
-                    tokenStream.ungetToken();
-                    handler.addList(pn, pn2);
-                    break;
-                }
-
-                MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
-
-                Node init = assignExpr(location == InForInit ? InProhibited : InAllowed,
-                                       yieldHandling, TripledotProhibited);
-                if (!init)
-                    return null();
-
-                // Ban the nonsensical |for (var V = E1 in E2);| where V is a
-                // destructuring pattern.  See bug 1164741 for background.
-                if (location == InForInit && kind == PNK_VAR) {
-                    TokenKind afterInit;
-                    if (!tokenStream.peekToken(&afterInit))
-                        return null();
-                    if (afterInit == TOK_IN) {
-                        report(ParseError, false, init, JSMSG_INVALID_FOR_INOF_DECL_WITH_INIT,
-                               "in");
-                        return null();
-                    }
-                }
-
-                if (!bindBeforeInitializer && !checkDestructuringPattern(&data, pn2))
-                    return null();
-
-                pn2 = handler.newBinary(PNK_ASSIGN, pn2, init);
-                if (!pn2)
-                    return null();
-
-                handler.addList(pn, pn2);
-                break;
-            }
-
-            if (tt != TOK_NAME) {
-                if (tt == TOK_YIELD) {
-                    if (!checkYieldNameValidity())
-                        return null();
-                } else {
-                    report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME);
-                    return null();
-                }
-            }
-
-            RootedPropertyName name(context, tokenStream.currentName());
-            pn2 = newBindingNode(name, kind == PNK_VAR, varContext);
-            if (!pn2)
-                return null();
-            if (data.isConst())
-                handler.setFlag(pn2, PND_CONST);
-            data.setNameNode(pn2);
-
-            handler.addList(pn, pn2);
-
-            bool matched;
-            // The '=' context after a variable name in a declaration is an
-            // opportunity for ASI, and thus for the next token to start an
-            // ExpressionStatement:
-            //
-            //  var foo   // VariableDeclaration
-            //  /bar/g;   // ExpressionStatement
-            //
-            // Therefore we must get the token here as Operand.
-            if (!tokenStream.matchToken(&matched, TOK_ASSIGN, TokenStream::Operand))
-                return null();
-            if (!matched) {
-                tokenStream.addModifierException(TokenStream::NoneIsOperand);
-
-                if (data.isConst() && location == NotInForInit) {
-                    report(ParseError, false, null(), JSMSG_BAD_CONST_DECL);
-                    return null();
-                }
-
-                if (!data.bind(name, this))
-                    return null();
-            } else {
-                if (psimple)
-                    *psimple = false;
-
-                // In ES6, lexical bindings may not be accessed until
-                // initialized. So a declaration of the form |let x = x| results
-                // in a ReferenceError, as the 'x' on the RHS is accessing the let
-                // binding before it is initialized.
-                //
-                // If we are not parsing a let declaration, bind the name
-                // now. Otherwise we must wait until after parsing the initializing
-                // assignment.
-                bool bindBeforeInitializer = kind != PNK_LET && kind != PNK_CONST;
-                if (bindBeforeInitializer && !data.bind(name, this))
-                    return null();
-
-                Node init = assignExpr(location == InForInit ? InProhibited : InAllowed,
-                                       yieldHandling, TripledotProhibited);
-                if (!init)
-                    return null();
-
-                // Ignore an initializer if we have a for-in loop declaring a
-                // |var| with an initializer: |for (var v = ... in ...);|.
-                // Warn that this syntax is invalid so that developers looking
-                // in the console know to fix this.  ES<6 permitted the
-                // initializer while ES6 doesn't; ignoring it seems the best
-                // way to incrementally move to ES6 semantics.
-                bool performAssignment = true;
-                if (location == InForInit && kind == PNK_VAR) {
-                    TokenKind afterInit;
-                    if (!tokenStream.peekToken(&afterInit))
-                        return null();
-                    if (afterInit == TOK_IN) {
-                        performAssignment = false;
-                        if (!report(ParseWarning, pc->sc->strict(), init,
-                                    JSMSG_INVALID_FOR_INOF_DECL_WITH_INIT, "in"))
-                        {
-                            return null();
-                        }
-                    }
-                }
-
-                if (performAssignment) {
-                    if (!bindBeforeInitializer && !data.bind(name, this))
-                        return null();
-
-                    if (!handler.finishInitializerAssignment(pn2, init))
-                        return null();
-                }
-            }
-
-            handler.setLexicalDeclarationOp(pn2, data.op());
-            handler.setEndPosition(pn, pn2);
-        } while (false);
-
-        bool matched;
+        data.initLexical(HoistVars, op, blockObj, JSMSG_TOO_MANY_LOCALS);
+
+    bool matched;
+    bool initialDeclaration = true;
+    do {
+        MOZ_ASSERT_IF(!initialDeclaration && forHeadKind,
+                      *forHeadKind == PNK_FORHEAD);
+
+        TokenKind tt;
+        if (!tokenStream.getToken(&tt))
+            return null();
+
+        Node binding = (tt == TOK_LB || tt == TOK_LC)
+                       ? declarationPattern(decl, tt, &data, initialDeclaration, yieldHandling,
+                                            forHeadKind, forInOrOfExpression)
+                       : declarationName(decl, tt, &data, initialDeclaration, yieldHandling,
+                                         forHeadKind, forInOrOfExpression);
+        if (!binding)
+            return null();
+
+        handler.addList(decl, binding);
+
+        if (forHeadKind && *forHeadKind != PNK_FORHEAD)
+            break;
+
+        initialDeclaration = false;
+
         if (!tokenStream.matchToken(&matched, TOK_COMMA))
             return null();
-        if (!matched)
-            break;
-    }
-
-    return pn;
+    } while (matched);
+
+    return decl;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::checkAndPrepareLexical(PrepareLexicalKind prepareWhat,
                                                  const TokenPos& errorPos)
 {
     /*
@@ -4680,16 +4824,31 @@ CurrentLexicalStaticBlock(ParseContext<F
         return &pc->innermostStaticScope()->as<StaticBlockObject>();
     MOZ_ASSERT(pc->atBodyLevel() &&
                (!pc->sc->isGlobalContext() ||
                 HasNonSyntacticStaticScopeChain(pc->innermostStaticScope())));
     return nullptr;
 }
 
 template <>
+void
+Parser<SyntaxParseHandler>::assertCurrentLexicalStaticBlockIs(ParseContext<SyntaxParseHandler>* pc,
+                                                              Handle<StaticBlockObject*> blockObj)
+{
+}
+
+template <>
+void
+Parser<FullParseHandler>::assertCurrentLexicalStaticBlockIs(ParseContext<FullParseHandler>* pc,
+                                                            Handle<StaticBlockObject*> blockObj)
+{
+    MOZ_ASSERT(CurrentLexicalStaticBlock(pc) == blockObj);
+}
+
+template <>
 bool
 Parser<FullParseHandler>::prepareAndBindInitializedLexicalWithNode(HandlePropertyName name,
                                                                    PrepareLexicalKind prepareWhat,
                                                                    ParseNode* pn,
                                                                    const TokenPos& pos)
 {
     BindData<FullParseHandler> data(context);
     if (!checkAndPrepareLexical(prepareWhat, pos))
@@ -4741,22 +4900,23 @@ Parser<FullParseHandler>::lexicalDeclara
      * is the VariableEnvironment, i.e., body-level lets are in
      * the same environment record as vars.
      *
      * However, they cannot be parsed exactly as vars, as ES6
      * requires that uninitialized lets throw ReferenceError on use.
      *
      * See 8.1.1.1.6 and the note in 13.2.1.
      */
-    ParseNodeKind kind = isConst ? PNK_CONST : PNK_LET;
-    ParseNode* pn = variables(yieldHandling, kind, NotInForInit,
-                              nullptr, CurrentLexicalStaticBlock(pc), HoistVars);
-    if (!pn)
-        return null();
-    return MatchOrInsertSemicolonAfterExpression(tokenStream) ? pn : nullptr;
+    ParseNode* decl =
+        declarationList(yieldHandling, isConst ? PNK_CONST : PNK_LET,
+                        CurrentLexicalStaticBlock(pc));
+    if (!decl || !MatchOrInsertSemicolonAfterExpression(tokenStream))
+        return null();
+
+    return decl;
 }
 
 template <>
 SyntaxParseHandler::Node
 Parser<SyntaxParseHandler>::lexicalDeclaration(YieldHandling, bool)
 {
     JS_ALWAYS_FALSE(abortIfSyntaxParser());
     return SyntaxParseHandler::NodeFailure;
@@ -5225,17 +5385,17 @@ Parser<FullParseHandler>::exportDeclarat
         const ClassNode& cls = kid->as<ClassNode>();
         MOZ_ASSERT(cls.names());
         if (!addExportName(cls.names()->innerBinding()->pn_atom))
             return null();
         break;
       }
 
       case TOK_VAR:
-        kid = variables(YieldIsName, PNK_VAR, NotInForInit);
+        kid = declarationList(YieldIsName, PNK_VAR);
         if (!kid)
             return null();
         if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
             return null();
         if (!addExportNamesForDeclaration(kid))
             return null();
         break;
 
@@ -5415,69 +5575,198 @@ Parser<ParseHandler>::whileStatement(Yie
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::matchInOrOf(bool* isForInp, bool* isForOfp)
 {
     TokenKind tt;
     if (!tokenStream.getToken(&tt))
         return false;
+
     *isForInp = tt == TOK_IN;
     *isForOfp = tt == TOK_NAME && tokenStream.currentToken().name() == context->names().of;
     if (!*isForInp && !*isForOfp) {
         tokenStream.ungetToken();
     } else {
         if (tt == TOK_NAME && !checkUnescapedName())
             return false;
     }
+
+    MOZ_ASSERT_IF(*isForInp || *isForOfp, *isForInp != *isForOfp);
     return true;
 }
 
-template <>
+template <class ParseHandler>
 bool
-Parser<FullParseHandler>::isValidForStatementLHS(ParseNode* pn1, JSVersion version,
-                                                 bool isForDecl, bool isForEach,
-                                                 ParseNodeKind headKind)
-{
-    if (isForDecl)
-        return pn1->pn_count < 2 && !pn1->isKind(PNK_CONST);
-
-    switch (pn1->getKind()) {
-      case PNK_ARRAY:
-      case PNK_CALL:
-      case PNK_DOT:
-      case PNK_ELEM:
-      case PNK_NAME:
-      case PNK_OBJECT:
-        return true;
-
-      default:
+Parser<ParseHandler>::validateForInOrOfLHSExpression(Node target)
+{
+    if (handler.isUnparenthesizedDestructuringPattern(target))
+        return checkDestructuringPattern(nullptr, target);
+
+    // All other permitted targets are simple.
+    if (!reportIfNotValidSimpleAssignmentTarget(target, ForInOrOfTarget))
         return false;
-    }
-}
-
-template <>
+
+    if (handler.isPropertyAccess(target))
+        return true;
+
+    if (handler.maybeNameAnyParentheses(target)) {
+        // The arguments/eval identifiers are simple in non-strict mode code,
+        // but warn to discourage use nonetheless.
+        if (!reportIfArgumentsEvalTarget(target))
+            return false;
+
+        handler.adjustGetToSet(target);
+        handler.markAsAssigned(target);
+        return true;
+    }
+
+    if (handler.isFunctionCall(target))
+        return makeSetCall(target, JSMSG_BAD_FOR_LEFTSIDE);
+
+    report(ParseError, false, target, JSMSG_BAD_FOR_LEFTSIDE);
+    return false;
+}
+
+template <class ParseHandler>
 bool
-Parser<FullParseHandler>::checkForHeadConstInitializers(ParseNode* pn1)
-{
-    if (!pn1->isKind(PNK_CONST))
+Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
+                                   ParseNodeKind* forHeadKind,
+                                   Node* forInitialPart,
+                                   Maybe<AutoPushStmtInfoPC>& letStmt,
+                                   MutableHandle<StaticBlockObject*> blockObj,
+                                   Node* forLetImpliedBlock,
+                                   Node* forInOrOfExpression)
+{
+    MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LP));
+
+    TokenKind tt;
+    if (!tokenStream.peekToken(&tt, TokenStream::Operand))
+        return null();
+
+    // Super-duper easy case: |for (;| is a C-style for-loop with no init
+    // component.
+    if (tt == TOK_SEMI) {
+        *forInitialPart = null();
+        *forHeadKind = PNK_FORHEAD;
         return true;
-
-    for (ParseNode* assign = pn1->pn_head; assign; assign = assign->pn_next) {
-        MOZ_ASSERT(assign->isKind(PNK_ASSIGN) || assign->isKind(PNK_NAME));
-        if (assign->isKind(PNK_NAME) && !assign->isAssigned())
+    }
+
+    // Parsing after |for (var| is also relatively simple (from this method's
+    // point of view).  No block-related work complicates matters, so delegate
+    // to Parser::declaration.
+    if (tt == TOK_VAR) {
+        tokenStream.consumeKnownToken(tt, TokenStream::Operand);
+
+        // Pass null for block object because |var| declarations don't use one.
+        *forInitialPart = declarationList(yieldHandling, PNK_VAR, nullptr, forHeadKind,
+                                          forInOrOfExpression);
+        return *forInitialPart != null();
+    }
+
+    // Otherwise we have a lexical declaration or an expression.
+
+    // For-in loop backwards compatibility requires that |let| starting a
+    // for-loop that's not a (new to ES6) for-of loop, in non-strict mode code,
+    // parse as an identifier.  (|let| in for-of is always a declaration.)
+    // Thus we must can't just sniff out TOK_CONST/TOK_LET here.  :-(
+    bool parsingLexicalDeclaration = false;
+    bool letIsIdentifier = false;
+    if (tt == TOK_LET || tt == TOK_CONST) {
+        parsingLexicalDeclaration = true;
+        tokenStream.consumeKnownToken(tt, TokenStream::Operand);
+    } else if (tt == TOK_NAME && tokenStream.nextName() == context->names().let) {
+        // Check for the backwards-compatibility corner case in sloppy
+        // mode like |for (let in e)| where the 'let' token should be
+        // parsed as an identifier.
+        if (!peekShouldParseLetDeclaration(&parsingLexicalDeclaration, TokenStream::Operand))
+            return false;
+
+        letIsIdentifier = !parsingLexicalDeclaration;
+    }
+
+    if (parsingLexicalDeclaration) {
+        handler.disableSyntaxParser();
+
+        // Set up the block chain for the lexical declaration.
+        blockObj.set(StaticBlockObject::create(context));
+        if (!blockObj)
+            return false;
+        blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
+        letStmt.emplace(*this, StmtType::BLOCK);
+        *forLetImpliedBlock = pushLetScope(blockObj, *letStmt);
+        if (!*forLetImpliedBlock)
             return false;
-        // PNK_ASSIGN nodes (destructuring assignment) are always assignments.
-    }
-    return true;
-}
-
-template <>
-ParseNode*
-Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
+        (*letStmt)->isForLetBlock = true;
+
+        assertCurrentLexicalStaticBlockIs(pc, blockObj);
+        *forInitialPart = declarationList(yieldHandling, tt == TOK_CONST ? PNK_CONST : PNK_LET,
+                                          blockObj, forHeadKind, forInOrOfExpression);
+        return *forInitialPart != null();
+    }
+
+    // Finally, handle for-loops that start with expressions.  Pass
+    // |InProhibited| so that |in| isn't parsed in a RelationalExpression as a
+    // binary operator.  |in| makes it a for-in loop, *not* an |in| expression.
+    *forInitialPart = expr(InProhibited, yieldHandling, TripledotProhibited);
+    if (!*forInitialPart)
+        return false;
+
+    bool isForIn, isForOf;
+    if (!matchInOrOf(&isForIn, &isForOf))
+        return false;
+
+    // If we don't encounter 'in'/'of', we have a for(;;) loop.  We've handled
+    // the init expression; the caller handles the rest.  Allow the Operand
+    // modifier when regetting: Operand must be used to examine the ';' in
+    // |for (;|, and our caller handles this case and that.
+    if (!isForIn && !isForOf) {
+        *forHeadKind = PNK_FORHEAD;
+        tokenStream.addModifierException(TokenStream::OperandIsNone);
+        return true;
+    }
+
+    MOZ_ASSERT(isForIn != isForOf);
+
+    // In a for-of loop, 'let' that starts the loop head is a |let| keyword,
+    // per the [lookahead ≠ let] restriction on the LeftHandSideExpression
+    // variant of such loops.  Expressions that start with |let| can't be used
+    // here.
+    //
+    //   var let = {};
+    //   for (let.prop of [1]) // BAD
+    //     break;
+    //
+    // See ES6 13.7.
+    if (isForOf && letIsIdentifier) {
+        report(ParseError, false, *forInitialPart, JSMSG_LET_STARTING_FOROF_LHS);
+        return false;
+    }
+
+    *forHeadKind = isForIn ? PNK_FORIN : PNK_FOROF;
+
+    if (!validateForInOrOfLHSExpression(*forInitialPart))
+        return false;
+
+    // Finally, parse the iterated expression, making the for-loop's closing
+    // ')' the next token.
+    *forInOrOfExpression = expressionAfterForInOrOf(*forHeadKind, yieldHandling);
+    return *forInOrOfExpression != null();
+}
+
+template <class ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::cloneForInOrOfDeclarationForAssignment(Node decl)
+{
+    return cloneLeftHandSide(handler.singleBindingFromDeclaration(decl));
+}
+
+template <class ParseHandler>
+typename ParseHandler::Node
+Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
     uint32_t begin = pos().begin;
 
     AutoPushStmtInfoPC forStmt(*this, StmtType::FOR_LOOP);
 
     bool isForEach = false;
     unsigned iflags = 0;
@@ -5494,432 +5783,205 @@ Parser<FullParseHandler>::forStatement(Y
                 if (!report(ParseWarning, pc->sc->strict(), null(), JSMSG_DEPRECATED_FOR_EACH))
                     return null();
             }
         }
     }
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
 
-    // True if we have 'for (var/let/const ...)'.
-    bool isForDecl = false;
+    // PNK_FORHEAD, PNK_FORIN, or PNK_FOROF depending on the loop type.
+    ParseNodeKind headKind;
+
+    // |x| in either |for (x; ...; ...)| or |for (x in/of ...)|.
+    Node startNode;
 
     // The next three variables are used to implement `for (let/const ...)`.
     //
     // We generate an implicit block, wrapping the whole loop, to store loop
     // variables declared this way. Note that if the loop uses `for (var...)`
     // instead, those variables go on some existing enclosing scope, so no
     // implicit block scope is created.
     //
     // All three variables remain null/none if the loop is any other form.
     //
     // blockObj is the static block object for the implicit block scope.
     RootedStaticBlockObject blockObj(context);
 
+    // The PNK_LEXICALSCOPE node containing blockObj's ObjectBox.
+    Node forLetImpliedBlock = null();
+
     // letStmt is the BLOCK StmtInfo for the implicit block.
     //
     // Caution: `letStmt.emplace()` creates some Rooted objects. Rooteds must
     // be created/destroyed in FIFO order. Therefore adding a Rooted in this
     // function, between this point and the .emplace() call below, would trip
     // assertions.
     Maybe<AutoPushStmtInfoPC> letStmt;
 
-    // The PNK_LEXICALSCOPE node containing blockObj's ObjectBox.
-    ParseNode* forLetImpliedBlock = nullptr;
-
-    // True if a 'let' token at the head is parsed as an identifier instead of
-    // as starting a declaration.
-    bool letIsIdentifier = false;
-
-    // Set to 'x' in 'for (x; ...; ...)' or 'for (x in ...)'.
-    ParseNode* pn1;
-
-    TokenStream::Modifier modifier = TokenStream::Operand;
+    // The expression being iterated over, for for-in/of loops only.  Unused
+    // for for(;;) loops.
+    Node iteratedExpr;
+
+    // Parse the entirety of the loop-head for a for-in/of loop (so the next
+    // token is the closing ')'):
+    //
+    //   for (... in/of ...) ...
+    //                     ^next token
+    //
+    // ...OR, parse up to the first ';' in a C-style for-loop:
+    //
+    //   for (...; ...; ...) ...
+    //           ^next token
+    //
+    // In either case the subsequent token can be consistently accessed using
+    // TokenStream::None semantics.
+    if (!forHeadStart(yieldHandling, &headKind, &startNode, letStmt, &blockObj,
+                      &forLetImpliedBlock, &iteratedExpr))
     {
-        TokenKind tt;
-        if (!tokenStream.peekToken(&tt, TokenStream::Operand))
-            return null();
-        if (tt == TOK_SEMI) {
-            pn1 = nullptr;
-        } else {
-            // Set pn1 to a variable list or an initializing expression.
-            //
-            // Pass |InForInit| to Parser::variables when parsing declarations
-            // to trigger |for|-specific parsing for that one position.  In a
-            // normal variable declaration, any initializer may be an |in|
-            // expression.  But for declarations at the start of a for-loop
-            // head, initializers can't contain |in|.  (Such syntax conflicts
-            // with ES5's |for (var i = 0 in foo)| syntax, removed in ES6, that
-            // we "support" by ignoring the |= 0|.)
-            if (tt == TOK_VAR) {
-                isForDecl = true;
-                tokenStream.consumeKnownToken(tt, TokenStream::Operand);
-                pn1 = variables(yieldHandling, PNK_VAR, InForInit);
-            } else if (tt == TOK_LET || tt == TOK_CONST ||
-                       (tt == TOK_NAME && tokenStream.nextName() == context->names().let)) {
-                handler.disableSyntaxParser();
-
-                // Check for the backwards-compatibility corner case in sloppy
-                // mode like |for (let in e)| where the 'let' token should be
-                // parsed as an identifier.
-                bool parseDecl;
-                if (tt == TOK_NAME) {
-                    if (!peekShouldParseLetDeclaration(&parseDecl, TokenStream::Operand))
-                        return null();
-                    letIsIdentifier = !parseDecl;
-                } else {
-                    parseDecl = true;
-                    tokenStream.consumeKnownToken(tt, TokenStream::Operand);
-                }
-
-                if (parseDecl) {
-                    bool constDecl = tt == TOK_CONST;
-                    isForDecl = true;
-
-                    // Initialize the enclosing scope manually for the call to
-                    // |variables| below.
-                    blockObj = StaticBlockObject::create(context);
-                    if (!blockObj)
-                        return null();
-                    blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
-                    letStmt.emplace(*this, StmtType::BLOCK);
-                    forLetImpliedBlock = pushLetScope(blockObj, *letStmt);
-                    if (!forLetImpliedBlock)
-                        return null();
-                    (*letStmt)->isForLetBlock = true;
-
-                    MOZ_ASSERT(CurrentLexicalStaticBlock(pc) == blockObj);
-                    pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit,
-                                    nullptr, blockObj, HoistVars);
-                } else {
-                    pn1 = expr(InProhibited, yieldHandling, TripledotProhibited);
-                }
-            } else {
-                // Pass |InProhibited| when parsing an expression so that |in|
-                // isn't parsed in a RelationalExpression as a binary operator.
-                // In this context, |in| is part of a for-in loop -- *not* part
-                // of a binary expression.
-                pn1 = expr(InProhibited, yieldHandling, TripledotProhibited);
-            }
-            if (!pn1)
-                return null();
-            modifier = TokenStream::None;
-        }
-    }
-
-    MOZ_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST));
-    MOZ_ASSERT(letStmt.isSome() == (isForDecl && (pn1->isOp(JSOP_DEFLET) || pn1->isOp(JSOP_DEFCONST))));
-
-    // If there's an |in| keyword here, it's a for-in loop, by dint of careful
-    // parsing of |pn1|.
-    ParseNode* pn2;      /* forHead->pn_kid2 */
-    ParseNode* pn3;      /* forHead->pn_kid3 */
-    ParseNodeKind headKind = PNK_FORHEAD;
-    if (pn1) {
-        bool isForIn, isForOf;
-        if (!matchInOrOf(&isForIn, &isForOf))
-            return null();
-
-        // In for-in loops, a 'let' token may be used as an identifier for
-        // backwards-compatibility reasons, e.g., |for (let in e)|. In for-of
-        // loops, a 'let' token is never parsed as an identifier. Forbid
-        // trying to parse a for-of loop if we have parsed a 'let' token as an
-        // identifier above.
-        //
-        // See ES6 13.7.5.1.
-        if (isForIn)
-            headKind = PNK_FORIN;
-        else if (isForOf && !letIsIdentifier)
-            headKind = PNK_FOROF;
-    }
-
+        return null();
+    }
+
+    MOZ_ASSERT(headKind == PNK_FORIN || headKind == PNK_FOROF || headKind == PNK_FORHEAD);
+
+    Node pn1;
+    Node pn2;
+    Node pn3;
+    TokenStream::Modifier modifier;
     if (headKind == PNK_FOROF || headKind == PNK_FORIN) {
+        // |target| is the LeftHandSideExpression or declaration to which the
+        // per-iteration value (an arbitrary value exposed by the iteration
+        // protocol, or a string naming a property) is assigned.
+        Node target = startNode;
+
         /*
          * Parse the rest of the for/in or for/of head.
          *
          * Here pn1 is everything to the left of 'in' or 'of'. At the end of
          * this block, pn1 is a decl or nullptr, pn2 is the assignment target
          * that receives the enumeration value each iteration, and pn3 is the
          * rhs of 'in'.
          */
         if (headKind == PNK_FOROF) {
             forStmt->type = StmtType::FOR_OF_LOOP;
             if (isForEach) {
-                report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
+                report(ParseError, false, startNode, JSMSG_BAD_FOR_EACH_LOOP);
                 return null();
             }
         } else {
             forStmt->type = StmtType::FOR_IN_LOOP;
             iflags |= JSITER_ENUMERATE;
         }
 
-        /* Check that the left side of the 'in' or 'of' is valid. */
-        if (!isValidForStatementLHS(pn1, versionNumber(), isForDecl, isForEach, headKind)) {
-            report(ParseError, false, pn1, JSMSG_BAD_FOR_LEFTSIDE);
-            return null();
-        }
-
         /*
          * After the following if-else, pn2 will point to the name or
          * destructuring pattern on in's left. pn1 will point to the decl, if
          * any, else nullptr. Note that the "declaration with initializer" case
          * rewrites the loop-head, moving the decl and setting pn1 to nullptr.
          */
-        if (isForDecl) {
-            pn2 = pn1->pn_head;
-            if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr()) || pn2->isKind(PNK_ASSIGN)) {
-                MOZ_ASSERT(!(headKind == PNK_FORIN && pn1->isKind(PNK_VAR)),
-                           "Parser::variables should have ignored the "
-                           "initializer in the ES5-sanctioned, ES6-prohibited "
-                           "|for (var ... = ... in ...)| syntax");
-
-                // Otherwise, this bizarre |for (const/let x = ... in/of ...)|
-                // loop isn't valid ES6 and has never been permitted in
-                // SpiderMonkey.
-                report(ParseError, false, pn2, JSMSG_INVALID_FOR_INOF_DECL_WITH_INIT,
-                       headKind == PNK_FOROF ? "of" : "in");
-                return null();
-            }
+        if (handler.isDeclarationList(target)) {
+            pn1 = target;
+
+            // Make a copy of the declaration that can be passed to
+            // BytecodeEmitter::emitAssignment.
+            pn2 = cloneForInOrOfDeclarationForAssignment(target);
+            if (!pn2)
+                return null();
         } else {
-            /* Not a declaration. */
             MOZ_ASSERT(!letStmt);
-            pn2 = pn1;
-            pn1 = nullptr;
+            pn1 = null();
+            pn2 = target;
 
             if (!checkAndMarkAsAssignmentLhs(pn2, PlainAssignment))
                 return null();
         }
 
-        pn3 = (headKind == PNK_FOROF)
-              ? assignExpr(InAllowed, yieldHandling, TripledotProhibited)
-              : expr(InAllowed, yieldHandling, TripledotProhibited);
-        if (!pn3)
-            return null();
+        pn3 = iteratedExpr;
+
+        if (handler.maybeNameAnyParentheses(pn2)) {
+            // Beware 'for (arguments in ...)' with or without a 'var'.
+            handler.markAsAssigned(pn2);
+        }
+
+        // Parser::declaration consumed everything up to the closing ')'.  That
+        // token follows an {Assignment,}Expression, so the next token must be
+        // consumed as if an operator continued the expression, i.e. as None.
         modifier = TokenStream::None;
-
-        if (isForDecl) {
-            /*
-             * pn2 is part of a declaration. Make a copy that can be passed to
-             * BytecodeEmitter::emitAssignment.
-             */
-            pn2 = cloneLeftHandSide(pn2);
-            if (!pn2)
-                return null();
-        }
-
-        ParseNodeKind kind2 = pn2->getKind();
-        MOZ_ASSERT(kind2 != PNK_ASSIGN, "forStatement TOK_ASSIGN");
-
-        if (kind2 == PNK_NAME) {
-            /* Beware 'for (arguments in ...)' with or without a 'var'. */
-            pn2->markAsAssigned();
-        }
     } else {
+        Node init = startNode;
+
         if (isForEach) {
             reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP);
             return null();
         }
 
-        MOZ_ASSERT(headKind == PNK_FORHEAD);
-
-        if (letStmt) {
-            // Ensure here that the previously-unchecked assignment mandate for
-            // const declarations holds.
-            if (!checkForHeadConstInitializers(pn1)) {
-                report(ParseError, false, nullptr, JSMSG_BAD_CONST_DECL);
-                return null();
-            }
-        }
-
-        /* Parse the loop condition or null into pn2. */
-        MUST_MATCH_TOKEN_MOD(TOK_SEMI, modifier, JSMSG_SEMI_AFTER_FOR_INIT);
+        // Look for an operand: |for (;| means we might have already examined
+        // this semicolon with that modifier.
+        MUST_MATCH_TOKEN_MOD(TOK_SEMI, TokenStream::Operand, JSMSG_SEMI_AFTER_FOR_INIT);
+
         TokenKind tt;
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
+
+        Node test;
+        TokenStream::Modifier mod;
         if (tt == TOK_SEMI) {
-            pn2 = nullptr;
-            modifier = TokenStream::Operand;
+            test = null();
+            mod = TokenStream::Operand;
         } else {
-            pn2 = expr(InAllowed, yieldHandling, TripledotProhibited);
-            if (!pn2)
-                return null();
-            modifier = TokenStream::None;
-        }
-
-        /* Parse the update expression or null into pn3. */
-        MUST_MATCH_TOKEN_MOD(TOK_SEMI, modifier, JSMSG_SEMI_AFTER_FOR_COND);
+            test = expr(InAllowed, yieldHandling, TripledotProhibited);
+            if (!test)
+                return null();
+            mod = TokenStream::None;
+        }
+
+        MUST_MATCH_TOKEN_MOD(TOK_SEMI, mod, JSMSG_SEMI_AFTER_FOR_COND);
+
         if (!tokenStream.peekToken(&tt, TokenStream::Operand))
             return null();
+
+        Node update;
         if (tt == TOK_RP) {
-            pn3 = nullptr;
-            modifier = TokenStream::Operand;
+            update = null();
+            mod = TokenStream::Operand;
         } else {
-            pn3 = expr(InAllowed, yieldHandling, TripledotProhibited);
-            if (!pn3)
-                return null();
-            modifier = TokenStream::None;
-        }
+            update = expr(InAllowed, yieldHandling, TripledotProhibited);
+            if (!update)
+                return null();
+            mod = TokenStream::None;
+        }
+
+        modifier = mod;
+        pn1 = init;
+        pn2 = test;
+        pn3 = update;
     }
 
     MUST_MATCH_TOKEN_MOD(TOK_RP, modifier, JSMSG_PAREN_AFTER_FOR_CTRL);
 
     TokenPos headPos(begin, pos().end);
-    ParseNode* forHead = handler.newForHead(headKind, pn1, pn2, pn3, headPos);
+    Node forHead = handler.newForHead(headKind, pn1, pn2, pn3, headPos);
     if (!forHead)
         return null();
 
-    /* Parse the loop body. */
-    ParseNode* body = statement(yieldHandling);
+    Node body = statement(yieldHandling);
     if (!body)
         return null();
 
-    ParseNode* forLoop = handler.newForStatement(begin, forHead, body, iflags);
+    Node forLoop = handler.newForStatement(begin, forHead, body, iflags);
     if (!forLoop)
         return null();
 
     if (forLetImpliedBlock) {
-        forLetImpliedBlock->pn_expr = forLoop;
-        forLetImpliedBlock->pn_pos = forLoop->pn_pos;
+        handler.initForLetBlock(forLetImpliedBlock, forLoop);
         return forLetImpliedBlock;
     }
     return forLoop;
 }
 
-template <>
-SyntaxParseHandler::Node
-Parser<SyntaxParseHandler>::forStatement(YieldHandling yieldHandling)
-{
-    /*
-     * 'for' statement parsing is fantastically complicated and requires being
-     * able to inspect the parse tree for previous parts of the 'for'. Syntax
-     * parsing of 'for' statements is thus done separately, and only handles
-     * the types of 'for' statements likely to be seen in web content.
-     */
-    MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
-
-    AutoPushStmtInfoPC forStmt(*this, StmtType::FOR_LOOP);
-
-    /* Don't parse 'for each' loops. */
-    if (allowsForEachIn()) {
-        TokenKind tt;
-        if (!tokenStream.peekToken(&tt))
-            return null();
-        // Not all "yield" tokens are names, but the ones that aren't names are
-        // invalid in this context anyway.
-        if (tt == TOK_NAME || tt == TOK_YIELD) {
-            JS_ALWAYS_FALSE(abortIfSyntaxParser());
-            return null();
-        }
-    }
-
-    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
-
-    /* True if we have 'for (var ...)'. */
-    bool isForDecl = false;
-    bool simpleForDecl = true;
-
-    /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
-    Node lhsNode;
-
-    TokenStream::Modifier modifier = TokenStream::Operand;
-    {
-        TokenKind tt;
-        if (!tokenStream.peekToken(&tt, TokenStream::Operand))
-            return null();
-        if (tt == TOK_SEMI) {
-            lhsNode = null();
-        } else {
-            /* Set lhsNode to a var list or an initializing expression. */
-            if (tt == TOK_VAR) {
-                isForDecl = true;
-                tokenStream.consumeKnownToken(tt, TokenStream::Operand);
-                lhsNode = variables(yieldHandling, PNK_VAR, InForInit, &simpleForDecl);
-            } else if (tt == TOK_CONST || tt == TOK_LET ||
-                       (tt == TOK_NAME && tokenStream.nextName() == context->names().let))
-            {
-                JS_ALWAYS_FALSE(abortIfSyntaxParser());
-                return null();
-            } else {
-                lhsNode = expr(InProhibited, yieldHandling, TripledotProhibited);
-            }
-            if (!lhsNode)
-                return null();
-            modifier = TokenStream::None;
-        }
-    }
-
-    // If there's an |in| keyword here, it's a for-in loop, by dint of careful
-    // parsing of |pn1|.
-    bool isForIn = false, isForOf = false;
-    if (lhsNode) {
-        if (!matchInOrOf(&isForIn, &isForOf))
-            return null();
-    }
-    if (isForIn || isForOf) {
-        /* Parse the rest of the for/in or for/of head. */
-        forStmt->type = isForOf ? StmtType::FOR_OF_LOOP : StmtType::FOR_IN_LOOP;
-
-        /* Check that the left side of the 'in' or 'of' is valid. */
-        if (!isForDecl &&
-            !handler.maybeNameAnyParentheses(lhsNode) &&
-            !handler.isPropertyAccess(lhsNode))
-        {
-            JS_ALWAYS_FALSE(abortIfSyntaxParser());
-            return null();
-        }
-
-        if (!simpleForDecl) {
-            JS_ALWAYS_FALSE(abortIfSyntaxParser());
-            return null();
-        }
-
-        if (!isForDecl && !checkAndMarkAsAssignmentLhs(lhsNode, PlainAssignment))
-            return null();
-
-        if (!(isForIn
-              ? expr(InAllowed, yieldHandling, TripledotProhibited)
-              : assignExpr(InAllowed, yieldHandling, TripledotProhibited)))
-        {
-            return null();
-        }
-        modifier = TokenStream::None;
-    } else {
-        /* Parse the loop condition or null. */
-        MUST_MATCH_TOKEN_MOD(TOK_SEMI, modifier, JSMSG_SEMI_AFTER_FOR_INIT);
-        TokenKind tt;
-        if (!tokenStream.peekToken(&tt, TokenStream::Operand))
-            return null();
-        modifier = TokenStream::Operand;
-        if (tt != TOK_SEMI) {
-            if (!expr(InAllowed, yieldHandling, TripledotProhibited))
-                return null();
-            modifier = TokenStream::None;
-        }
-
-        /* Parse the update expression or null. */
-        MUST_MATCH_TOKEN_MOD(TOK_SEMI, modifier, JSMSG_SEMI_AFTER_FOR_COND);
-        if (!tokenStream.peekToken(&tt, TokenStream::Operand))
-            return null();
-        modifier = TokenStream::Operand;
-        if (tt != TOK_RP) {
-            if (!expr(InAllowed, yieldHandling, TripledotProhibited))
-                return null();
-            modifier = TokenStream::None;
-        }
-    }
-
-    MUST_MATCH_TOKEN_MOD(TOK_RP, modifier, JSMSG_PAREN_AFTER_FOR_CTRL);
-
-    /* Parse the loop body. */
-    if (!statement(yieldHandling))
-        return null();
-
-    return SyntaxParseHandler::NodeGeneric;
-}
-
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_SWITCH));
     uint32_t begin = pos().begin;
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
@@ -6901,35 +6963,46 @@ Parser<SyntaxParseHandler>::classDefinit
     return SyntaxParseHandler::NodeFailure;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::shouldParseLetDeclaration(bool* parseDeclOut)
 {
     TokenKind tt;
-    *parseDeclOut = false;
-
     if (!tokenStream.peekToken(&tt))
         return false;
 
-    switch (tt) {
-      case TOK_NAME:
-        // |let let| is disallowed per ES6 13.3.1.1.
-        *parseDeclOut = tokenStream.nextName() != context->names().let;
-        break;
-
-      case TOK_LC:
-      case TOK_LB:
-        // |let {| and |let [| are destructuring declarations.
+    if (tt == TOK_NAME) {
+        // |let| followed by a name is a lexical declaration.  This is so even
+        // if the name is on a new line.  ASI applies *only* if an offending
+        // token not allowed by the grammar is encountered, and there's no
+        // [no LineTerminator here] restriction in LexicalDeclaration or
+        // ForDeclaration forbidding a line break.
+        //
+        // It's a tricky point, but this is true *even if* the name is "let", a
+        // name that can't be bound by LexicalDeclaration or ForDeclaration.
+        // Per ES6 5.3, static semantics early errors are validated *after*
+        // determining productions matching the source text.  So in this
+        // example:
+        //
+        //   let   // ASI opportunity...except not
+        //   let;
+        //
+        // the text matches LexicalDeclaration.  *Then* static semantics in
+        // ES6 13.3.1.1 (corresponding to the LexicalDeclaration production
+        // just chosen), per ES6 5.3, are validated to recognize the Script as
+        // invalid.  It can't be evaluated, so a SyntaxError is thrown.
         *parseDeclOut = true;
-        break;
-
-      default:
-        break;
+    } else if (tt == TOK_LB || tt == TOK_LC) {
+        *parseDeclOut = true;
+    } else {
+        // Whatever we have isn't a declaration.  Either it's an expression, or
+        // it's invalid: expression-parsing code will decide.
+        *parseDeclOut = false;
     }
 
     return true;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::peekShouldParseLetDeclaration(bool* parseDeclOut,
@@ -6972,17 +7045,17 @@ Parser<ParseHandler>::statement(YieldHan
 
     switch (tt) {
       // BlockStatement[?Yield, ?Return]
       case TOK_LC:
         return blockStatement(yieldHandling);
 
       // VariableStatement[?Yield]
       case TOK_VAR: {
-        Node pn = variables(yieldHandling, PNK_VAR, NotInForInit);
+        Node pn = declarationList(yieldHandling, PNK_VAR);
         if (!pn)
             return null();
         if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
             return null();
         return pn;
       }
 
       // EmptyStatement
@@ -7018,27 +7091,30 @@ Parser<ParseHandler>::statement(YieldHan
             if (!checkYieldNameValidity())
                 return null();
             return labeledStatement(yieldHandling);
         }
         return expressionStatement(yieldHandling);
       }
 
       case TOK_NAME: {
-        // 'let' is a contextual keyword in sloppy node. In strict mode, it is
-        // always lexed as TOK_LET except following case:
+        // 'let' is a contextual keyword outside strict mode.  In strict mode
+        // it's always tokenized as TOK_LET except in this one weird case:
         //
-        //   "use strict"
-        //   let a = 1;
+        //   "use strict" // ExpressionStatement, terminated by ASI
+        //   let a = 1;   // LexicalDeclaration
         //
-        // There 'let' is lexed as TOK_NAME before parsing directive.
+        // We can't apply strict mode until we know "use strict" is the entire
+        // statement, but we can't know "use strict" is the entire statement
+        // until we see the next token.  So 'let' is still TOK_NAME here.
         if (tokenStream.currentName() == context->names().let) {
             bool parseDecl;
             if (!shouldParseLetDeclaration(&parseDecl))
                 return null();
+
             if (parseDecl)
                 return lexicalDeclaration(yieldHandling, /* isConst = */ false);
         }
 
         TokenKind next;
         if (!tokenStream.peekToken(&next))
             return null();
         if (next == TOK_COLON)
@@ -7642,16 +7718,20 @@ Parser<ParseHandler>::reportIfNotValidSi
       case KeyedDestructuringAssignment:
         errnum = JSMSG_BAD_DESTRUCT_TARGET;
         break;
 
       case PlainAssignment:
       case CompoundAssignment:
         errnum = JSMSG_BAD_LEFTSIDE_OF_ASS;
         break;
+
+      case ForInOrOfTarget:
+        errnum = JSMSG_BAD_FOR_LEFTSIDE;
+        break;
     }
 
     report(ParseError, pc->sc->strict(), target, errnum, extra);
     return false;
 }
 
 template <typename ParseHandler>
 bool
@@ -8534,17 +8614,17 @@ Parser<ParseHandler>::comprehensionFor(G
     if (!blockObj)
         return null();
 
     // Initialize the enclosing scope manually for the call to |bind|
     // below, which is before the call to |pushLetScope|.
     blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
 
     data.initLexical(DontHoistVars, JSOP_DEFLET, blockObj, JSMSG_TOO_MANY_LOCALS);
-    Node decls = handler.newList(PNK_LET, lhs);
+    Node decls = handler.newComprehensionBinding(lhs);
     if (!decls)
         return null();
     data.setNameNode(lhs);
     if (!data.bind(name, this))
         return null();
     Node letScope = pushLetScope(blockObj, stmtInfo);
     if (!letScope)
         return null();
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1,20 +1,20 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+/* JS parser. */
+
 #ifndef frontend_Parser_h
 #define frontend_Parser_h
 
-/*
- * JS parser definitions.
- */
+#include "mozilla/Maybe.h"
 
 #include "jspubtd.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FullParseHandler.h"
 #include "frontend/ParseMaps.h"
 #include "frontend/ParseNode.h"
 #include "frontend/SharedContext.h"
@@ -664,37 +664,99 @@ class Parser : private JS::AutoGCRooter,
     Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling);
     Node functionExpr(InvokedPrediction invoked = PredictUninvoked);
     Node statements(YieldHandling yieldHandling);
 
     Node blockStatement(YieldHandling yieldHandling);
     Node ifStatement(YieldHandling yieldHandling);
     Node doWhileStatement(YieldHandling yieldHandling);
     Node whileStatement(YieldHandling yieldHandling);
+
     Node forStatement(YieldHandling yieldHandling);
+    bool forHeadStart(YieldHandling yieldHandling,
+                      ParseNodeKind* forHeadKind,
+                      Node* forInitialPart,
+                      mozilla::Maybe<AutoPushStmtInfoPC>& letStmt,
+                      MutableHandle<StaticBlockObject*> blockObj,
+                      Node* forLetImpliedBlock,
+                      Node* forInOrOfExpression);
+    bool validateForInOrOfLHSExpression(Node target);
+    Node expressionAfterForInOrOf(ParseNodeKind forHeadKind, YieldHandling yieldHandling);
+
+    void assertCurrentLexicalStaticBlockIs(ParseContext<ParseHandler>* pc,
+                                           Handle<StaticBlockObject*> blockObj);
+
     Node switchStatement(YieldHandling yieldHandling);
     Node continueStatement(YieldHandling yieldHandling);
     Node breakStatement(YieldHandling yieldHandling);
     Node returnStatement(YieldHandling yieldHandling);
     Node withStatement(YieldHandling yieldHandling);
     Node labeledStatement(YieldHandling yieldHandling);
     Node throwStatement(YieldHandling yieldHandling);
     Node tryStatement(YieldHandling yieldHandling);
     Node debuggerStatement();
 
     Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst);
     Node importDeclaration();
     Node exportDeclaration();
     Node expressionStatement(YieldHandling yieldHandling,
                              InvokedPrediction invoked = PredictUninvoked);
-    Node variables(YieldHandling yieldHandling,
-                   ParseNodeKind kind,
-                   ForInitLocation location,
-                   bool* psimple = nullptr, StaticBlockObject* blockObj = nullptr,
-                   VarContext varContext = HoistVars);
+
+    // Declaration parsing.  The main entrypoint is Parser::declarationList,
+    // with sub-functionality split out into the remaining methods.
+
+    // |blockObj| may be non-null only when |kind| corresponds to a lexical
+    // declaration (that is, PNK_LET or PNK_CONST).
+    //
+    // The for* parameters, for normal declarations, should be null/ignored.
+    // They should be non-null only when Parser::forHeadStart parses a
+    // declaration at the start of a for-loop head.
+    //
+    // In this case, on success |*forHeadKind| is PNK_FORHEAD, PNK_FORIN, or
+    // PNK_FOROF, corresponding to the three for-loop kinds.  The precise value
+    // indicates what was parsed.
+    //
+    // If parsing recognized a for(;;) loop, the next token is the ';' within
+    // the loop-head that separates the init/test parts.
+    //
+    // Otherwise, for for-in/of loops, the next token is the ')' ending the
+    // loop-head.  Additionally, the expression that the loop iterates over was
+    // parsed into |*forInOrOfExpression|.
+    Node declarationList(YieldHandling yieldHandling,
+                         ParseNodeKind kind,
+                         StaticBlockObject* blockObj = nullptr,
+                         ParseNodeKind* forHeadKind = nullptr,
+                         Node* forInOrOfExpression = nullptr);
+
+    // The items in a declaration list are either patterns or names, with or
+    // without initializers.  These two methods parse a single pattern/name and
+    // any associated initializer -- and if parsing an |initialDeclaration|
+    // will, if parsing in a for-loop head (as specified by |forHeadKind| being
+    // non-null), consume additional tokens up to the closing ')' in a
+    // for-in/of loop head, returning the iterated expression in
+    // |*forInOrOfExpression|.  (An "initial declaration" is the first
+    // declaration in a declaration list: |a| but not |b| in |var a, b|, |{c}|
+    // but not |d| in |let {c} = 3, d|.)
+    Node declarationPattern(Node decl, TokenKind tt, BindData<ParseHandler>* data,
+                            bool initialDeclaration, YieldHandling yieldHandling,
+                            ParseNodeKind* forHeadKind, Node* forInOrOfExpression);
+    Node declarationName(Node decl, TokenKind tt, BindData<ParseHandler>* data,
+                         bool initialDeclaration, YieldHandling yieldHandling,
+                         ParseNodeKind* forHeadKind, Node* forInOrOfExpression);
+
+    // Having parsed a name (not found in a destructuring pattern) declared by
+    // a declaration, with the current token being the '=' separating the name
+    // from its initializer, parse and bind that initializer -- and possibly
+    // consume trailing in/of and subsequent expression, if so directed by
+    // |forHeadKind|.
+    bool initializerInNameDeclaration(Node decl, Node binding, Handle<PropertyName*> name,
+                                      BindData<ParseHandler>* data, bool initialDeclaration,
+                                      YieldHandling yieldHandling, ParseNodeKind* forHeadKind,
+                                      Node* forInOrOfExpression);
+
     Node expr(InHandling inHandling, YieldHandling yieldHandling,
               TripledotHandling tripledotHandling,
               InvokedPrediction invoked = PredictUninvoked);
     Node assignExpr(InHandling inHandling, YieldHandling yieldHandling,
                     TripledotHandling tripledotHandling,
                     InvokedPrediction invoked = PredictUninvoked);
     Node assignExprWithoutYield(YieldHandling yieldHandling, unsigned err);
     Node yieldExpression(InHandling inHandling);
@@ -778,17 +840,18 @@ class Parser : private JS::AutoGCRooter,
 #endif
     }
 
     enum AssignmentFlavor {
         PlainAssignment,
         CompoundAssignment,
         KeyedDestructuringAssignment,
         IncrementAssignment,
-        DecrementAssignment
+        DecrementAssignment,
+        ForInOrOfTarget
     };
 
     bool checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor);
     bool matchInOrOf(bool* isForInp, bool* isForOfp);
 
     bool checkFunctionArguments();
 
     bool defineFunctionThis();
@@ -797,20 +860,16 @@ class Parser : private JS::AutoGCRooter,
     bool makeDefIntoUse(Definition* dn, Node pn, HandleAtom atom);
     bool bindLexicalFunctionName(HandlePropertyName funName, ParseNode* pn);
     bool bindBodyLevelFunctionName(HandlePropertyName funName, ParseNode** pn);
     bool checkFunctionDefinition(HandlePropertyName funName, Node* pn, FunctionSyntaxKind kind,
                                  bool* pbodyProcessed, Node* assignmentForAnnexBOut);
     bool finishFunctionDefinition(Node pn, FunctionBox* funbox, Node body);
     bool addFreeVariablesFromLazyFunction(JSFunction* fun, ParseContext<ParseHandler>* pc);
 
-    bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
-                                ParseNodeKind headKind);
-    bool checkForHeadConstInitializers(Node pn1);
-
     // Use when the current token is TOK_NAME and is known to be 'let'.
     bool shouldParseLetDeclaration(bool* parseDeclOut);
 
     // Use when the lookahead token is TOK_NAME and is known to be 'let'. If a
     // let declaration should be parsed, the TOK_NAME token of 'let' is
     // consumed. Otherwise, the current token remains the TOK_NAME token of
     // 'let'.
     bool peekShouldParseLetDeclaration(bool* parseDeclOut, TokenStream::Modifier modifier);
@@ -872,18 +931,20 @@ class Parser : private JS::AutoGCRooter,
     bool checkDestructuringObject(BindData<ParseHandler>* data, Node objectPattern);
     bool checkDestructuringName(BindData<ParseHandler>* data, Node expr);
 
     bool bindInitialized(BindData<ParseHandler>* data, HandlePropertyName name, Node pn);
     bool bindInitialized(BindData<ParseHandler>* data, Node pn);
     bool bindUninitialized(BindData<ParseHandler>* data, HandlePropertyName name, Node pn);
     bool bindUninitialized(BindData<ParseHandler>* data, Node pn);
     bool makeSetCall(Node node, unsigned errnum);
+
+    Node cloneForInOrOfDeclarationForAssignment(Node decl);
+    Node cloneLeftHandSide(Node opn);
     Node cloneDestructuringDefault(Node opn);
-    Node cloneLeftHandSide(Node opn);
     Node cloneParseTree(Node opn);
 
     Node newNumber(const Token& tok) {
         return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
     }
 
     static bool
     bindDestructuringArg(BindData<ParseHandler>* data,
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -453,44 +453,43 @@ SharedContext::asModuleBox()
 // invalidate DebugScope proxies for unaliased locals in a generator frame, as
 // the generator frame will be copied out to the heap and released only by GC.
 inline bool
 SharedContext::allLocalsAliased()
 {
     return bindingsAccessedDynamically() || (isFunctionBox() && asFunctionBox()->isGenerator());
 }
 
+// NOTE: If you add a new type of statement that is a scope, add it between
+//       WITH and CATCH, or you'll break StmtInfoBase::linksScope.  If you add
+//       a non-looping statement type, add it before DO_LOOP or you'll break
+//       StmtInfoBase::isLoop().
+#define FOR_EACH_STATEMENT_TYPE(macro) \
+    macro(LABEL, "label statement") \
+    macro(IF, "if statement") \
+    macro(ELSE, "else statement") \
+    macro(SEQ, "destructuring body") \
+    macro(BLOCK, "block") \
+    macro(SWITCH, "switch statement") \
+    macro(WITH, "with statement") \
+    macro(CATCH, "catch block") \
+    macro(TRY, "try block") \
+    macro(FINALLY, "finally block") \
+    macro(SUBROUTINE, "finally block") \
+    macro(DO_LOOP, "do loop") \
+    macro(FOR_LOOP, "for loop") \
+    macro(FOR_IN_LOOP, "for/in loop") \
+    macro(FOR_OF_LOOP, "for/of loop") \
+    macro(WHILE_LOOP, "while loop") \
+    macro(SPREAD, "spread")
 
-/*
- * NB: If you add a new type of statement that is a scope, add it between
- * STMT_WITH and STMT_CATCH, or you will break StmtInfoBase::linksScope. If you
- * add a non-looping statement type, add it before STMT_DO_LOOP or you will
- * break StmtInfoBase::isLoop().
- *
- * Also remember to keep the statementName array in BytecodeEmitter.cpp in
- * sync.
- */
 enum class StmtType : uint16_t {
-    LABEL,                 /* labeled statement:  L: s */
-    IF,                    /* if (then) statement */
-    ELSE,                  /* else clause of if statement */
-    SEQ,                   /* synthetic sequence of statements */
-    BLOCK,                 /* compound statement: { s1[;... sN] } */
-    SWITCH,                /* switch statement */
-    WITH,                  /* with statement */
-    CATCH,                 /* catch block */
-    TRY,                   /* try block */
-    FINALLY,               /* finally block */
-    SUBROUTINE,            /* gosub-target subroutine body */
-    DO_LOOP,               /* do/while loop statement */
-    FOR_LOOP,              /* for loop statement */
-    FOR_IN_LOOP,           /* for/in loop statement */
-    FOR_OF_LOOP,           /* for/of loop statement */
-    WHILE_LOOP,            /* while loop statement */
-    SPREAD,                /* spread operator (pseudo for/of) */
+#define DECLARE_STMTTYPE_ENUM(name, desc) name,
+    FOR_EACH_STATEMENT_TYPE(DECLARE_STMTTYPE_ENUM)
+#undef DECLARE_STMTTYPE_ENUM
     LIMIT
 };
 
 /*
  * A comment on the encoding of the js::StmtType enum and StmtInfoBase
  * type-testing methods:
  *
  * StmtInfoBase::maybeScope() tells whether a statement type is always, or may
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -37,21 +37,26 @@ class SyntaxParseHandler
 
   public:
     enum Node {
         NodeFailure = 0,
         NodeGeneric,
         NodeGetProp,
         NodeStringExprStatement,
         NodeReturn,
-        NodeHoistableDeclaration,
         NodeBreak,
         NodeThrow,
         NodeEmptyStatement,
 
+        NodeVarDeclaration,
+        NodeLetDeclaration,
+        NodeConstDeclaration,
+
+        NodeFunctionDefinition,
+
         // This is needed for proper assignment-target handling.  ES6 formally
         // requires function calls *not* pass IsValidSimpleAssignmentTarget,
         // but at last check there were still sites with |f() = 5| and similar
         // in code not actually executed (or at least not executed enough to be
         // noticed).
         NodeFunctionCall,
 
         // Nodes representing *parenthesized* IsValidSimpleAssignmentTarget
@@ -326,34 +331,47 @@ class SyntaxParseHandler
 
     Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeElement; }
 
     bool addCatchBlock(Node catchList, Node letBlock,
                        Node catchName, Node catchGuard, Node catchBody) { return true; }
 
     bool setLastFunctionArgumentDefault(Node funcpn, Node pn) { return true; }
     void setLastFunctionArgumentDestructuring(Node funcpn, Node pn) {}
-    Node newFunctionDefinition() { return NodeHoistableDeclaration; }
+    Node newFunctionDefinition() { return NodeFunctionDefinition; }
     void setFunctionBody(Node pn, Node kid) {}
     void setFunctionBox(Node pn, FunctionBox* funbox) {}
-    Node newFunctionDefinitionForAnnexB(Node pn, Node assignment) { return NodeHoistableDeclaration; }
+    Node newFunctionDefinitionForAnnexB(Node pn, Node assignment) { return NodeFunctionDefinition; }
     void addFunctionArgument(Node pn, Node argpn) {}
 
     Node newForStatement(uint32_t begin, Node forHead, Node body, unsigned iflags) {
         return NodeGeneric;
     }
 
     Node newComprehensionFor(uint32_t begin, Node forHead, Node body) {
         return NodeGeneric;
     }
 
+    Node newComprehensionBinding(Node kid) {
+        // Careful: we're asking this well after the name was parsed, so the
+        // value returned may not correspond to |kid|'s actual name.  But it
+        // *will* be truthy iff |kid| was a name, so we're safe.
+        MOZ_ASSERT(maybeUnparenthesizedName(kid));
+        return NodeGeneric;
+    }
+
     Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos& pos) {
         return NodeGeneric;
     }
 
+    void initForLetBlock(Node forLetImpliedBlock, Node nestedForLoop) {
+        MOZ_ASSERT(forLetImpliedBlock == NodeGeneric); // per newForStatement
+        MOZ_ASSERT(nestedForLoop == NodeGeneric); // per newLexicalScope
+    }
+
     Node newLexicalScope(ObjectBox* blockbox) { return NodeGeneric; }
     void setLexicalScopeBody(Node block, Node body) {}
 
     Node newLetBlock(Node vars, Node block, const TokenPos& pos) {
         return NodeGeneric;
     }
 
     bool finishInitializerAssignment(Node pn, Node init) { return true; }
@@ -369,48 +387,96 @@ class SyntaxParseHandler
 
     void setPosition(Node pn, const TokenPos& pos) {}
     TokenPos getPosition(Node pn) {
         return tokenStream.currentToken().pos;
     }
 
     Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
         MOZ_ASSERT(kind != PNK_VAR);
+        MOZ_ASSERT(kind != PNK_LET);
+        MOZ_ASSERT(kind != PNK_CONST);
         return NodeGeneric;
     }
     Node newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
-        return NodeGeneric;
-    }
-    Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
-        MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
-        return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
+        return newList(kind, op);
     }
     Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
-        MOZ_ASSERT(kind != PNK_VAR);
-        return NodeGeneric;
+        return newList(kind, op);
+    }
+
+    Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
+        if (kind == PNK_VAR)
+            return NodeVarDeclaration;
+        if (kind == PNK_LET)
+            return NodeLetDeclaration;
+        MOZ_ASSERT(kind == PNK_CONST);
+        return NodeConstDeclaration;
     }
     Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
-        MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
-        return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
+        return newDeclarationList(kind, op);
+    }
+
+    bool isDeclarationList(Node node) {
+        return node == NodeVarDeclaration ||
+               node == NodeLetDeclaration ||
+               node == NodeConstDeclaration;
+    }
+
+    bool declarationIsVar(Node node) {
+        MOZ_ASSERT(isDeclarationList(node));
+        return node == NodeVarDeclaration;
+    }
+
+    bool declarationIsLet(Node node) {
+        MOZ_ASSERT(isDeclarationList(node));
+        return node == NodeLetDeclaration;
+    }
+
+    bool declarationIsConst(Node node) {
+        MOZ_ASSERT(isDeclarationList(node));
+        return node == NodeConstDeclaration;
+    }
+
+    Node singleBindingFromDeclaration(Node decl) {
+        MOZ_ASSERT(isDeclarationList(decl));
+
+        // This is, unfortunately, very dodgy.  Obviously NodeVarDeclaration
+        // can store no info on the arbitrary number of bindings it could
+        // contain.
+        //
+        // But this method is called only for cloning for-in/of declarations
+        // as initialization targets.  That context simplifies matters.  If the
+        // binding is a single name, it'll always syntax-parse (or it would
+        // already have been rejected as assigning/binding a forbidden name).
+        // Otherwise the binding is a destructuring pattern.  But syntax
+        // parsing would *already* have aborted when it saw a destructuring
+        // pattern.  So we can just say any old thing here, because the only
+        // time we'll be wrong is a case that syntax parsing has already
+        // rejected.  Use NodeUnparenthesizedName so the SyntaxParseHandler
+        // Parser::cloneLeftHandSide can assert it sees only this.
+        return NodeUnparenthesizedName;
     }
 
     Node newCatchList() {
         return newList(PNK_CATCHLIST, JSOP_NOP);
     }
 
     Node newCommaExpressionList(Node kid) {
         return NodeUnparenthesizedCommaExpr;
     }
 
     void addList(Node list, Node kid) {
         MOZ_ASSERT(list == NodeGeneric ||
                    list == NodeUnparenthesizedArray ||
                    list == NodeUnparenthesizedObject ||
                    list == NodeUnparenthesizedCommaExpr ||
-                   list == NodeHoistableDeclaration ||
+                   list == NodeVarDeclaration ||
+                   list == NodeLetDeclaration ||
+                   list == NodeConstDeclaration ||
                    list == NodeFunctionCall);
     }
 
     Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs,
                        ParseContext<SyntaxParseHandler>* pc, JSOp op)
     {
         if (kind == PNK_ASSIGN)
             return NodeUnparenthesizedAssignment;
@@ -429,17 +495,19 @@ class SyntaxParseHandler
         return node == NodeUnparenthesizedAssignment;
     }
 
     bool isReturnStatement(Node node) {
         return node == NodeReturn;
     }
 
     bool isStatementPermittedAfterReturnStatement(Node pn) {
-        return pn == NodeHoistableDeclaration || pn == NodeBreak || pn == NodeThrow ||
+        return pn == NodeFunctionDefinition || pn == NodeVarDeclaration ||
+               pn == NodeBreak ||
+               pn == NodeThrow ||
                pn == NodeEmptyStatement;
     }
 
     bool isSuperBase(Node pn) {
         return pn == NodeSuperBase;
     }
 
     void setOp(Node pn, JSOp op) {}
--- a/js/src/jit-test/tests/asm.js/gating.js
+++ b/js/src/jit-test/tests/asm.js/gating.js
@@ -1,18 +1,20 @@
 // Check gating of shared memory features in asm.js (bug 1171540,
-// bug 1231624).
+// bug 1231624, bug 1231338).
 //
 // In asm.js, importing any atomic is a signal that shared memory is
 // being used.  If an atomic is imported, and if shared memory is
 // disabled in the build or in the run then a type error should be
 // signaled for the module at the end of the declaration section and
 // the module should not be an asm.js module.
 
-if (!this.SharedArrayBuffer || !isAsmJSCompilationAvailable())
+// Do not guard on the presence of SharedArrayBuffer, we test that later.
+
+if (!isAsmJSCompilationAvailable())
     quit(0);
 
 // This code is not run, we only care whether it compiles as asm.js.
 
 function module_a(stdlib, foreign, heap) {
     "use asm";
 
     var i32a = new stdlib.Int32Array(heap);
--- a/js/src/jit-test/tests/parser/letContextualKeyword.js
+++ b/js/src/jit-test/tests/parser/letContextualKeyword.js
@@ -11,19 +11,100 @@ function expectError(str) {
 
 eval(`let x = 42; assertEq(x, 42);`);
 eval(`var let = 42; assertEq(let, 42);`);
 eval(`let;`);
 eval(`[...let] = [];`);
 eval(`function let() { return 42; } assertEq(let(), 42);`)
 eval(`let {x:x} = {x:42}; assertEq(x, 42);`);
 eval(`let [x] = [42]; assertEq(x, 42);`);
+
 eval(`for (let x in [1]) { assertEq(x, "0"); }`);
+expectError(`for (const x in [1]) { assertEq(x, "0"); }`); // XXX bug 449811
+
 eval(`for (let x of [1]) { assertEq(x, 1); }`);
+expectError(`for (const x of [1]) { assertEq(x, 1); }`); // XXX bug 449811
+
 eval(`for (let i = 0; i < 1; i++) { assertEq(i, 0); }`);
+eval(`var done = false; for (const i = 0; !done; done = true) { assertEq(i, 0); }`);
+
+eval(`for (let of of [1]) { assertEq(of, 1); }`);
+expectError(`for (const of of [1]) { assertEq(of, 1); }`); // XXX bug 449811
+
+eval(`try { throw 17; } catch (let) { assertEq(let, 17); }`);
+eval(`try { throw [17]; } catch ([let]) { assertEq(let, 17); }`);
+eval(`try { throw { x: 17 }; } catch ({ x: let }) { assertEq(let, 17); }`);
+eval(`try { throw {}; } catch ({ x: let = 17 }) { assertEq(let, 17); }`);
+
+expectError(`try { throw [17, 42]; } catch ([let, let]) {}`);
+
 eval(`for (let in [1]) { assertEq(let, "0"); }`);
-eval(`for (let of of [1]) { assertEq(of, 1); }`);
-eval(`for (let/1;;) { break; }`);
+eval(`for (let / 1; ; ) { break; }`);
+expectError(`let = {}; for (let.x of;;);`);
 expectError(`for (let of [1]) { }`);
-expectError(`let let = 42;`);
+
+expectError(`for (let let in [1]) { }`);
+expectError(`for (const let in [1]) { }`);
+
+expectError(`for (let let of [1]) { }`);
+expectError(`for (const let of [1]) { }`);
+
+expectError(`for (let let = 17; false; ) { }`);
+expectError(`for (const let = 17; false; ) { }`);
+
+expectError(`for (let [let] = 17; false; ) { }`);
+expectError(`for (const [let] = 17; false; ) { }`);
+
+expectError(`for (let [let = 42] = 17; false; ) { }`);
+expectError(`for (const [let = 42] = 17; false; ) { }`);
+
+expectError(`for (let { x: let } = 17; false; ) { }`);
+expectError(`for (const { x: let } = 17; false; ) { }`);
+
+expectError(`for (let { x: let = 42 } = 17; false; ) { }`);
+expectError(`for (const { x: let = 42 } = 17; false; ) { }`);
+
+expectError("let\nlet;");
+expectError("const\nlet;");
+
+expectError(`let let = 17;`);
+expectError(`const let = 17;`);
+
+expectError(`let [let] = 17;`);
+expectError(`const [let] = 17;`);
+
+expectError(`let [let = 42] = 17;`);
+expectError(`const [let = 42] = 17;`);
+
+expectError(`let {let} = 17;`);
+expectError(`const {let} = 17;`);
+
+expectError(`let { let = 42 } = 17;`);
+expectError(`const { let = 42 } = 17;`);
+
+expectError(`let { x: let } = 17;`);
+expectError(`const { x: let } = 17;`);
+
+expectError(`let { x: let = 42 } = 17;`);
+expectError(`const { x: let = 42 } = 17;`);
+
+expectError(`let { ['y']: let } = 17;`);
+expectError(`const { ['y']: let } = 17;`);
+
+expectError(`let { ['y']: let = 42 } = 17;`);
+expectError(`const { ['y']: let = 42 } = 17;`);
+
+expectError(`let { x: [let] } = { x: 17 };`);
+expectError(`const { x: [let] } = { x: 17 };`);
+
+expectError(`let { x: [let = 42] } = { x: 17 };`);
+expectError(`const { x: [let = 42] } = { x: 17 };`);
+
+expectError(`let [foo, let] = 42;`);
+expectError(`const [foo, let] = 42;`);
+
+expectError(`let [foo, { let }] = [17, {}];`);
+expectError(`const [foo, { let }] = [17, {}];`);
+
 expectError(`"use strict"; var let = 42;`);
 expectError(`"use strict"; function let() {}`);
 expectError(`"use strict"; for (let of [1]) {}`);
+expectError(`"use strict"; try {} catch (let) {}`);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/sharedbuf/sab-gating.js
@@ -0,0 +1,8 @@
+// Check gating of shared memory features in plain js (bug 1231338).
+
+// Need this testing function to continue.
+if (!this.sharedMemoryEnabled)
+    quit(0);
+
+assertEq(sharedMemoryEnabled(), !!this.SharedArrayBuffer);
+assertEq(sharedMemoryEnabled(), !!this.Atomics);
--- a/js/src/jit/ExecutableAllocator.cpp
+++ b/js/src/jit/ExecutableAllocator.cpp
@@ -403,13 +403,9 @@ ExecutableAllocator::poisonCode(JSRuntim
         if (pool->isMarked()) {
             reprotectPool(rt, pool, Executable);
             pool->unmark();
         }
         pool->release();
     }
 }
 
-#if TARGET_OS_IPHONE
 bool ExecutableAllocator::nonWritableJitCode = true;
-#else
-bool ExecutableAllocator::nonWritableJitCode = false;
-#endif
--- a/js/src/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/jit/ExecutableAllocatorWin.cpp
@@ -121,16 +121,20 @@ ExceptionHandler(PEXCEPTION_RECORD excep
     return sJitExceptionHandler(exceptionRecord, context);
 }
 
 // For an explanation of the problem being solved here, see
 // SetJitExceptionFilter in jsfriendapi.h.
 static bool
 RegisterExecutableMemory(void* p, size_t bytes, size_t pageSize)
 {
+    DWORD oldProtect;
+    if (!VirtualProtect(p, pageSize, PAGE_READWRITE, &oldProtect))
+        return false;
+
     ExceptionHandlerRecord* r = reinterpret_cast<ExceptionHandlerRecord*>(p);
 
     // All these fields are specified to be offsets from the base of the
     // executable code (which is 'p'), even if they have 'Address' in their
     // names. In particular, exceptionHandler is a ULONG offset which is a
     // 32-bit integer. Since 'p' can be farther than INT32_MAX away from
     // sJitExceptionHandler, we must generate a little thunk inside the
     // record. The record is put on its own page so that we can take away write
@@ -153,17 +157,16 @@ RegisterExecutableMemory(void* p, size_t
     r->thunk[1]  = 0xb8;
     void* handler = JS_FUNC_TO_DATA_PTR(void*, ExceptionHandler);
     memcpy(&r->thunk[2], &handler, 8);
 
     // jmp rax
     r->thunk[10] = 0xff;
     r->thunk[11] = 0xe0;
 
-    DWORD oldProtect;
     if (!VirtualProtect(p, pageSize, PAGE_EXECUTE_READ, &oldProtect))
         return false;
 
     return RtlAddFunctionTable(&r->runtimeFunction, 1, reinterpret_cast<DWORD64>(p));
 }
 
 static void
 UnregisterExecutableMemory(void* p, size_t bytes, size_t pageSize)
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -176,16 +176,17 @@ JitRuntime::JitRuntime(JSRuntime* rt)
     argumentsRectifier_(nullptr),
     argumentsRectifierReturnAddr_(nullptr),
     invalidator_(nullptr),
     debugTrapHandler_(nullptr),
     baselineDebugModeOSRHandler_(nullptr),
     functionWrappers_(nullptr),
     osrTempData_(nullptr),
     preventBackedgePatching_(false),
+    backedgeTarget_(BackedgeLoopHeader),
     ionReturnOverride_(MagicValue(JS_ARG_POISON)),
     jitcodeGlobalTable_(nullptr)
 {
 }
 
 JitRuntime::~JitRuntime()
 {
     js_delete(functionWrappers_);
@@ -366,16 +367,22 @@ JitRuntime::patchIonBackedges(JSRuntime*
     } else {
         // We must be called from InterruptRunningJitCode, or a signal handler
         // triggered there. rt->handlingJitInterrupt() ensures we can't reenter
         // this code.
         MOZ_ASSERT(!preventBackedgePatching_);
         MOZ_ASSERT(rt->handlingJitInterrupt());
     }
 
+    // Do nothing if we know all backedges are already jumping to `target`.
+    if (backedgeTarget_ == target)
+        return;
+
+    backedgeTarget_ = target;
+
     backedgeExecAlloc_.makeAllWritable();
 
     // Patch all loop backedges in Ion code so that they either jump to the
     // normal loop header or to an interrupt handler each time they run.
     for (InlineListIterator<PatchableBackedge> iter(backedgeList_.begin());
          iter != backedgeList_.end();
          iter++)
     {
@@ -1142,21 +1149,19 @@ IonScript::copyPatchableBackedges(JSCont
         PatchableBackedge* patchableBackedge = &backedgeList()[i];
 
         info.backedge.fixup(&masm);
         CodeLocationJump backedge(code, info.backedge);
         CodeLocationLabel loopHeader(code, CodeOffset(info.loopHeader->offset()));
         CodeLocationLabel interruptCheck(code, CodeOffset(info.interruptCheck->offset()));
         new(patchableBackedge) PatchableBackedge(backedge, loopHeader, interruptCheck);
 
-        // Point the backedge to either of its possible targets, according to
-        // whether an interrupt is currently desired, matching the targets
-        // established by ensureIonCodeAccessible() above. We don't handle the
-        // interrupt immediately as the interrupt lock is held here.
-        if (cx->runtime()->hasPendingInterrupt())
+        // Point the backedge to either of its possible targets, matching the
+        // other backedges in the runtime.
+        if (jrt->backedgeTarget() == JitRuntime::BackedgeInterruptCheck)
             PatchBackedge(backedge, interruptCheck, JitRuntime::BackedgeInterruptCheck);
         else
             PatchBackedge(backedge, loopHeader, JitRuntime::BackedgeLoopHeader);
 
         jrt->addPatchableBackedge(patchableBackedge);
     }
 }
 
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -77,16 +77,23 @@ class PatchableBackedge : public InlineL
                       CodeLocationLabel loopHeader,
                       CodeLocationLabel interruptCheck)
       : backedge(backedge), loopHeader(loopHeader), interruptCheck(interruptCheck)
     {}
 };
 
 class JitRuntime
 {
+  public:
+    enum BackedgeTarget {
+        BackedgeLoopHeader,
+        BackedgeInterruptCheck
+    };
+
+  private:
     friend class JitCompartment;
 
     // Executable allocator for all code except asm.js code and Ion code with
     // patchable backedges (see below).
     ExecutableAllocator execAlloc_;
 
     // Executable allocator for Ion scripts with patchable backedges.
     ExecutableAllocator backedgeExecAlloc_;
@@ -147,17 +154,21 @@ class JitRuntime
 
     // Buffer for OSR from baseline to Ion. To avoid holding on to this for
     // too long, it's also freed in JitCompartment::mark and in EnterBaseline
     // (after returning from JIT code).
     uint8_t* osrTempData_;
 
     // If true, the signal handler to interrupt Ion code should not attempt to
     // patch backedges, as we're busy modifying data structures.
-    volatile bool preventBackedgePatching_;
+    mozilla::Atomic<bool> preventBackedgePatching_;
+
+    // Whether patchable backedges currently jump to the loop header or the
+    // interrupt check.
+    BackedgeTarget backedgeTarget_;
 
     // List of all backedges in all Ion code. The backedge edge list is accessed
     // asynchronously when the main thread is paused and preventBackedgePatching_
     // is false. Thus, the list must only be mutated while preventBackedgePatching_
     // is true.
     InlineList<PatchableBackedge> backedgeList_;
 
     // In certain cases, we want to optimize certain opcodes to typed instructions,
@@ -242,30 +253,28 @@ class JitRuntime
                 jrt_->preventBackedgePatching_ = prev_;
             }
         }
     };
 
     bool preventBackedgePatching() const {
         return preventBackedgePatching_;
     }
+    BackedgeTarget backedgeTarget() const {
+        return backedgeTarget_;
+    }
     void addPatchableBackedge(PatchableBackedge* backedge) {
         MOZ_ASSERT(preventBackedgePatching_);
         backedgeList_.pushFront(backedge);
     }
     void removePatchableBackedge(PatchableBackedge* backedge) {
         MOZ_ASSERT(preventBackedgePatching_);
         backedgeList_.remove(backedge);
     }
 
-    enum BackedgeTarget {
-        BackedgeLoopHeader,
-        BackedgeInterruptCheck
-    };
-
     void patchIonBackedges(JSRuntime* rt, BackedgeTarget target);
 
     JitCode* getVMWrapper(const VMFunction& f) const;
     JitCode* debugTrapHandler(JSContext* cx);
     JitCode* getBaselineDebugModeOSRHandler(JSContext* cx);
     void* getBaselineDebugModeOSRHandlerAddress(JSContext* cx, bool popFrameReg);
 
     JitCode* getGenericBailoutHandler() const {
--- a/js/src/jit/arm64/Assembler-arm64.cpp
+++ b/js/src/jit/arm64/Assembler-arm64.cpp
@@ -568,17 +568,21 @@ TraceDataRelocations(JSTracer* trc, uint
 
         // All pointers on AArch64 will have the top bits cleared.
         // If those bits are not cleared, this must be a Value.
         if (literal >> JSVAL_TAG_SHIFT) {
             jsval_layout layout;
             layout.asBits = literal;
             Value v = IMPL_TO_JSVAL(layout);
             TraceManuallyBarrieredEdge(trc, &v, "ion-masm-value");
-            *literalAddr = JSVAL_TO_IMPL(v).asBits;
+            if (*literalAddr != JSVAL_TO_IMPL(v).asBits) {
+                // Only update the code if the value changed, because the code
+                // is not writable if we're not moving objects.
+                *literalAddr = JSVAL_TO_IMPL(v).asBits;
+            }
 
             // TODO: When we can, flush caches here if a pointer was moved.
             continue;
         }
 
         // No barriers needed since the pointers are constants.
         TraceManuallyBarrieredGenericPointerEdge(trc, reinterpret_cast<gc::Cell**>(literalAddr),
                                                  "ion-masm-ptr");
--- a/js/src/jit/x86-shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.cpp
@@ -57,18 +57,21 @@ TraceDataRelocations(JSTracer* trc, uint
         // All pointers on x64 will have the top bits cleared. If those bits
         // are not cleared, this must be a Value.
         uintptr_t* word = reinterpret_cast<uintptr_t*>(ptr);
         if (*word >> JSVAL_TAG_SHIFT) {
             jsval_layout layout;
             layout.asBits = *word;
             Value v = IMPL_TO_JSVAL(layout);
             TraceManuallyBarrieredEdge(trc, &v, "ion-masm-value");
-            if (*word != JSVAL_TO_IMPL(v).asBits)
+            if (*word != JSVAL_TO_IMPL(v).asBits) {
+                // Only update the code if the Value changed, because the code
+                // is not writable if we're not moving objects.
                 *word = JSVAL_TO_IMPL(v).asBits;
+            }
             continue;
         }
 #endif
 
         // No barrier needed since these are constants.
         TraceManuallyBarrieredGenericPointerEdge(trc, reinterpret_cast<gc::Cell**>(ptr),
                                                  "ion-masm-ptr");
     }
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -195,18 +195,20 @@ MSG_DEF(JSMSG_BAD_BINDING,             1
 MSG_DEF(JSMSG_BAD_CONST_DECL,          0, JSEXN_SYNTAXERR, "missing = in const declaration")
 MSG_DEF(JSMSG_BAD_CONTINUE,            0, JSEXN_SYNTAXERR, "continue must be inside loop")
 MSG_DEF(JSMSG_BAD_DESTRUCT_ASS,        0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator")
 MSG_DEF(JSMSG_BAD_DESTRUCT_TARGET,     0, JSEXN_SYNTAXERR, "invalid destructuring target")
 MSG_DEF(JSMSG_BAD_DESTRUCT_PARENS,     0, JSEXN_SYNTAXERR, "destructuring patterns in assignments can't be parenthesized")
 MSG_DEF(JSMSG_BAD_DESTRUCT_DECL,       0, JSEXN_SYNTAXERR, "missing = in destructuring declaration")
 MSG_DEF(JSMSG_BAD_DUP_ARGS,            0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context")
 MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP,       0, JSEXN_SYNTAXERR, "invalid for each loop")
-MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE,        0, JSEXN_SYNTAXERR, "invalid for/in left-hand side")
-MSG_DEF(JSMSG_BAD_GENERATOR_RETURN,    1, JSEXN_TYPEERR, "generator function {0} returns a value")
+MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE,        0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side")
+MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding")
+MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS,  0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'")
+MSG_DEF(JSMSG_BAD_GENERATOR_RETURN,    1, JSEXN_TYPEERR,   "generator function {0} returns a value")
 MSG_DEF(JSMSG_BAD_YIELD_SYNTAX,        0, JSEXN_SYNTAXERR, "yield expression must be parenthesized")
 MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX,    0, JSEXN_SYNTAXERR, "generator expression must be parenthesized")
 MSG_DEF(JSMSG_BAD_GENEXP_BODY,         1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
 MSG_DEF(JSMSG_BAD_INCOP_OPERAND,       0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
 MSG_DEF(JSMSG_BAD_METHOD_DEF,          0, JSEXN_SYNTAXERR, "bad method definition")
 MSG_DEF(JSMSG_BAD_OCTAL,               1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
 MSG_DEF(JSMSG_BAD_OPERAND,             1, JSEXN_SYNTAXERR, "invalid {0} operand")
 MSG_DEF(JSMSG_BAD_PROP_ID,             0, JSEXN_SYNTAXERR, "invalid property id")
@@ -259,17 +261,17 @@ MSG_DEF(JSMSG_EQUAL_AS_ASSIGN,         0
 MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level of a module")
 MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY,     0, JSEXN_SYNTAXERR, "finally without try")
 MSG_DEF(JSMSG_FROM_AFTER_IMPORT_CLAUSE, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import clause")
 MSG_DEF(JSMSG_FROM_AFTER_EXPORT_STAR,  0, JSEXN_SYNTAXERR, "missing keyword 'from' after export *")
 MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT,     2, JSEXN_SYNTAXERR, "unexpected garbage after {0}, starting with {1}")
 MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER,    0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
 MSG_DEF(JSMSG_ILLEGAL_CHARACTER,       0, JSEXN_SYNTAXERR, "illegal character")
 MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
-MSG_DEF(JSMSG_INVALID_FOR_INOF_DECL_WITH_INIT,1,JSEXN_SYNTAXERR,"for-{0} loop head declarations may not have initializers")
+MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers")
 MSG_DEF(JSMSG_IN_AFTER_FOR_NAME,       0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for")
 MSG_DEF(JSMSG_LABEL_NOT_FOUND,         0, JSEXN_SYNTAXERR, "label not found")
 MSG_DEF(JSMSG_LET_CLASS_BINDING,       0, JSEXN_SYNTAXERR, "'let' is not a valid name for a class")
 MSG_DEF(JSMSG_LET_COMP_BINDING,        0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
 MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,   1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
 MSG_DEF(JSMSG_LEXICAL_DECL_LABEL,      1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled")
 MSG_DEF(JSMSG_FUNCTION_LABEL,          0, JSEXN_SYNTAXERR, "functions cannot be labelled")
 MSG_DEF(JSMSG_SLOPPY_FUNCTION_LABEL,   0, JSEXN_SYNTAXERR, "functions can only be labelled inside blocks")
@@ -306,17 +308,17 @@ MSG_DEF(JSMSG_PAREN_BEFORE_CATCH,      0
 MSG_DEF(JSMSG_PAREN_BEFORE_COND,       0, JSEXN_SYNTAXERR, "missing ( before condition")
 MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL,     0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
 MSG_DEF(JSMSG_PAREN_BEFORE_LET,        0, JSEXN_SYNTAXERR, "missing ( before let head")
 MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH,     0, JSEXN_SYNTAXERR, "missing ( before switch expression")
 MSG_DEF(JSMSG_PAREN_BEFORE_WITH,       0, JSEXN_SYNTAXERR, "missing ( before with-statement object")
 MSG_DEF(JSMSG_PAREN_IN_PAREN,          0, JSEXN_SYNTAXERR, "missing ) in parenthetical")
 MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
 MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list")
-MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch")
+MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_SYNTAXERR, "redeclaration of identifier '{0}' in catch")
 MSG_DEF(JSMSG_REDECLARED_PARAM,        1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}")
 MSG_DEF(JSMSG_RESERVED_ID,             1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
 MSG_DEF(JSMSG_REST_WITH_DEFAULT,       0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
 MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LEXICAL, 1, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level {0} declarations")
 MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups")
 MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND,     0, JSEXN_SYNTAXERR, "missing ; after for-loop condition")
 MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT,     0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer")
 MSG_DEF(JSMSG_SEMI_BEFORE_STMNT,       0, JSEXN_SYNTAXERR, "missing ; before statement")
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -608,16 +608,19 @@ if CONFIG['MOZ_ETW']:
     GENERATED_FILES = [
         'ETWProvider.h',
     ]
     # This will get the ETW provider resources into the library mozjs.dll
     RESFILE = 'ETWProvider.res'
 
 if CONFIG['NIGHTLY_BUILD']:
     DEFINES['ENABLE_BINARYDATA'] = True
+
+# Also in shell/moz.build
+if CONFIG['NIGHTLY_BUILD']:
     DEFINES['ENABLE_SHARED_ARRAY_BUFFER'] = True
     DEFINES['ENABLE_SIMD'] = True
 
 DEFINES['EXPORT_JS_API'] = True
 
 if CONFIG['JS_HAS_CTYPES']:
     DEFINES['JS_HAS_CTYPES'] = True
     for var in ('DLL_PREFIX', 'DLL_SUFFIX'):
--- a/js/src/shell/moz.build
+++ b/js/src/shell/moz.build
@@ -13,16 +13,20 @@ if CONFIG['JS_SHELL_NAME']:
 UNIFIED_SOURCES += [
     'js.cpp',
     'jsoptparse.cpp',
     'OSObject.cpp'
 ]
 
 DEFINES['EXPORT_JS_API'] = True
 
+# Also in ../moz.build
+if CONFIG['NIGHTLY_BUILD']:
+    DEFINES['ENABLE_SHARED_ARRAY_BUFFER'] = True
+
 if CONFIG['_MSC_VER']:
     # unnecessary PGO for js shell.  But gcc cannot turn off pgo because it is
     # necessary to link PGO lib on gcc when a object/static lib are compiled
     # for PGO.
     NO_PGO = True
 
 LOCAL_INCLUDES += [
     '!..',
--- a/js/src/tests/js1_6/Regress/regress-355002.js
+++ b/js/src/tests/js1_6/Regress/regress-355002.js
@@ -15,17 +15,17 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
-  expect = 'SyntaxError: invalid for/in left-hand side';
+  expect = 'SyntaxError: invalid for-in/of left-hand side';
   actual = '';
   try
   { 
     eval('for each (this in []) { }');
   }
   catch(ex)
   {
     actual = ex + '';
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -24,21 +24,21 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 338;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 339;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 432,
+static_assert(JSErr_Limit == 434,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext* cx)
--- a/layout/reftests/svg/filters/feComposite-2-ref.svg
+++ b/layout/reftests/svg/filters/feComposite-2-ref.svg
@@ -1,7 +1,9 @@
 <svg xmlns="http://www.w3.org/2000/svg">
 
 <rect x="0" y="0" width="50" height="100" fill="#00ff00"/>
 <rect x="0" y="0" width="50" height="100" fill="#ff0000" opacity="0.5"/>
 <rect x="50" y="0" width="50" height="100" fill="#ff0000" opacity="0.5"/>
 
+<rect x="100" y="0" width="50" height="100" fill="#808080"/>
+
 </svg>
--- a/layout/reftests/svg/filters/feComposite-2.svg
+++ b/layout/reftests/svg/filters/feComposite-2.svg
@@ -5,9 +5,23 @@
   <feComposite style="color-interpolation-filters:sRGB"
    in="flood" operator="over" in2="SourceGraphic"/>
 </filter>
 <g filter="url(#f1)">
   <rect x="0" y="0" width="50" height="100" fill="#00ff00"/>
   <rect x="50" y="0" width="50" height="100" fill="#00ff00" opacity="0"/>
 </g>
 
+<!-- Test that the arithmetic operator actually clamp the result -->
+<filter id="f2" filterUnits="userSpaceOnUse" primitiveUnits="userSpaceOnUse" style="color-interpolation-filters:sRGB">
+  <feFlood flood-color="#ffffff" result="flood" x="100" y="0" width="50" height="100"/>
+  <feComposite result="c" in="SourceGraphic" in2="flood" operator="arithmetic" k2="1" k3="1"/>
+  <feComponentTransfer in="c">
+    <feFuncR type="linear" slope="0.5"/>
+    <feFuncG type="linear" slope="0.5"/>
+    <feFuncB type="linear" slope="0.5"/>
+  </feComponentTransfer>
+</filter>
+<g filter="url(#f2)">
+  <rect x="100" y="0" width="50" height="100" fill="#ff0000"/>
+</g>
+
 </svg>
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -79,17 +79,17 @@ NS_NewComputedDOMStyle(dom::Element* aEl
  */
 struct nsComputedStyleMap
 {
   friend class nsComputedDOMStyle;
 
   struct Entry
   {
     // Create a pointer-to-member-function type.
-    typedef mozilla::dom::CSSValue* (nsComputedDOMStyle::*ComputeMethod)();
+    typedef already_AddRefed<CSSValue> (nsComputedDOMStyle::*ComputeMethod)();
 
     nsCSSProperty mProperty;
     ComputeMethod mGetter;
 
     bool IsLayoutFlushNeeded() const
     {
       return nsCSSProps::PropHasFlags(mProperty,
                                       CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH);
@@ -883,63 +883,63 @@ nsComputedDOMStyle::IndexedGetter(uint32
     aFound = false;
   }
 
   ClearCurrentStyleSources();
 }
 
 // Property getters...
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBinding()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleDisplay* display = StyleDisplay();
 
   if (display->mBinding) {
     val->SetURI(display->mBinding->GetURI());
   } else {
     val->SetIdent(eCSSKeyword_none);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetClear()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakType,
                                                nsCSSProps::kClearKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFloat()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mFloats,
                                                nsCSSProps::kFloatKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBottom()
 {
   return GetOffsetWidthFor(NS_SIDE_BOTTOM);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStackSizing()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(StyleXUL()->mStretchStack ? eCSSKeyword_stretch_to_fit :
                 eCSSKeyword_ignore);
-  return val;
+  return val.forget();
 }
 
 void
 nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
                                    nscolor aColor)
 {
   if (NS_GET_A(aColor) == 0) {
     aValue->SetIdent(eCSSKeyword_transparent);
@@ -958,138 +958,138 @@ nsComputedDOMStyle::SetToRGBAColor(nsROC
   red->SetNumber(NS_GET_R(aColor));
   green->SetNumber(NS_GET_G(aColor));
   blue->SetNumber(NS_GET_B(aColor));
   alpha->SetNumber(nsStyleUtil::ColorComponentToFloat(a));
 
   aValue->SetColor(rgbColor);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColor()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleColor()->mColor);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOpacity()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleDisplay()->mOpacity);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColumnCount()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleColumn* column = StyleColumn();
 
   if (column->mColumnCount == NS_STYLE_COLUMN_COUNT_AUTO) {
     val->SetIdent(eCSSKeyword_auto);
   } else {
     val->SetNumber(column->mColumnCount);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColumnWidth()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   // XXX fix the auto case. When we actually have a column frame, I think
   // we should return the computed column width.
   SetValueToCoord(val, StyleColumn()->mColumnWidth, true);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColumnGap()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleColumn* column = StyleColumn();
   if (column->mColumnGap.GetUnit() == eStyleUnit_Normal) {
     val->SetAppUnits(StyleFont()->mFont.size);
   } else {
     SetValueToCoord(val, StyleColumn()->mColumnGap, true);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColumnFill()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnFill,
                                    nsCSSProps::kColumnFillKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColumnRuleWidth()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetAppUnits(StyleColumn()->GetComputedColumnRuleWidth());
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColumnRuleStyle()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleColumn()->mColumnRuleStyle,
                                    nsCSSProps::kBorderStyleKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColumnRuleColor()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleColumn* column = StyleColumn();
   nscolor ruleColor;
   if (column->mColumnRuleColorIsForeground) {
     ruleColor = StyleColor()->mColor;
   } else {
     ruleColor = column->mColumnRuleColor;
   }
 
   SetToRGBAColor(val, ruleColor);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetContent()
 {
   const nsStyleContent *content = StyleContent();
 
   if (content->ContentCount() == 0) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
+    return val.forget();
   }
 
   if (content->ContentCount() == 1 &&
       content->ContentAt(0).mType == eStyleContentType_AltContent) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword__moz_alt_content);
-    return val;
-  }
-
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   for (uint32_t i = 0, i_end = content->ContentCount(); i < i_end; ++i) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
     const nsStyleContentData &data = content->ContentAt(i);
     switch (data.mType) {
       case eStyleContentType_String:
         {
@@ -1168,61 +1168,61 @@ nsComputedDOMStyle::DoGetContent()
       case eStyleContentType_AltContent:
       default:
         NS_NOTREACHED("unexpected type");
         break;
     }
     valueList->AppendCSSValue(val.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetCounterIncrement()
 {
   const nsStyleContent *content = StyleContent();
 
   if (content->CounterIncrementCount() == 0) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
-  }
-
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   for (uint32_t i = 0, i_end = content->CounterIncrementCount(); i < i_end; ++i) {
     RefPtr<nsROCSSPrimitiveValue> name = new nsROCSSPrimitiveValue;
     RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
 
     const nsStyleCounterData *data = content->GetCounterIncrementAt(i);
     nsAutoString escaped;
     nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
     name->SetString(escaped);
     value->SetNumber(data->mValue); // XXX This should really be integer
 
     valueList->AppendCSSValue(name.forget());
     valueList->AppendCSSValue(value.forget());
   }
 
-  return valueList;
+  return valueList.forget();
 }
 
 /* Convert the stored representation into a list of two values and then hand
  * it back.
  */
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTransformOrigin()
 {
   /* We need to build up a list of two values.  We'll call them
    * width and height.
    */
 
   /* Store things as a value list */
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   /* Now, get the values. */
   const nsStyleDisplay* display = StyleDisplay();
 
   RefPtr<nsROCSSPrimitiveValue> width = new nsROCSSPrimitiveValue;
   SetValueToCoord(width, display->mTransformOrigin[0], false,
                   &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
   valueList->AppendCSSValue(width.forget());
@@ -1235,95 +1235,95 @@ nsComputedDOMStyle::DoGetTransformOrigin
   if (display->mTransformOrigin[2].GetUnit() != eStyleUnit_Coord ||
       display->mTransformOrigin[2].GetCoordValue() != 0) {
     RefPtr<nsROCSSPrimitiveValue> depth = new nsROCSSPrimitiveValue;
     SetValueToCoord(depth, display->mTransformOrigin[2], false,
                     nullptr);
     valueList->AppendCSSValue(depth.forget());
   }
 
-  return valueList;
+  return valueList.forget();
 }
 
 /* Convert the stored representation into a list of two values and then hand
  * it back.
  */
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPerspectiveOrigin()
 {
   /* We need to build up a list of two values.  We'll call them
    * width and height.
    */
 
   /* Store things as a value list */
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   /* Now, get the values. */
   const nsStyleDisplay* display = StyleDisplay();
 
   RefPtr<nsROCSSPrimitiveValue> width = new nsROCSSPrimitiveValue;
   SetValueToCoord(width, display->mPerspectiveOrigin[0], false,
                   &nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
   valueList->AppendCSSValue(width.forget());
 
   RefPtr<nsROCSSPrimitiveValue> height = new nsROCSSPrimitiveValue;
   SetValueToCoord(height, display->mPerspectiveOrigin[1], false,
                   &nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
   valueList->AppendCSSValue(height.forget());
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPerspective()
 {
-    nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     SetValueToCoord(val, StyleDisplay()->mChildPerspective, false);
-    return val;
-}
-
-CSSValue*
+    return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackfaceVisibility()
 {
-    nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(
         nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBackfaceVisibility,
                                        nsCSSProps::kBackfaceVisibilityKTable));
-    return val;
-}
-
-CSSValue*
+    return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTransformStyle()
 {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(
         nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mTransformStyle,
                                        nsCSSProps::kTransformStyleKTable));
-    return val;
+    return val.forget();
 }
 
 /* If the property is "none", hand back "none" wrapped in a value.
  * Otherwise, compute the aggregate transform matrix and hands it back in a
  * "matrix" wrapper.
  */
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTransform()
 {
   /* First, get the display data.  We'll need it. */
   const nsStyleDisplay* display = StyleDisplay();
 
   /* If there are no transforms, then we should construct a single-element
    * entry and hand it back.
    */
   if (!display->mSpecifiedTransform) {
-    nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
     /* Set it to "none." */
     val->SetIdent(eCSSKeyword_none);
-    return val;
+    return val.forget();
   }
 
   /* Otherwise, we need to compute the current value of the transform matrix,
    * store it in a string, and hand it back to the caller.
    */
 
   /* Use the inner frame for the reference box.  If we don't have an inner
    * frame we use empty dimensions to allow us to continue (and percentage
@@ -1346,27 +1346,27 @@ nsComputedDOMStyle::DoGetTransform()
                                             mStyleContext->PresContext(),
                                             dummy,
                                             refBox,
                                             float(mozilla::AppUnitsPerCSSPixel()));
 
   return MatrixToCSSValue(matrix);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTransformBox()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
       nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mTransformBox,
                                      nsCSSProps::kTransformBoxKTable));
-  return val;
-}
-
-/* static */ nsROCSSPrimitiveValue*
+  return val.forget();
+}
+
+/* static */ already_AddRefed<nsROCSSPrimitiveValue>
 nsComputedDOMStyle::MatrixToCSSValue(const mozilla::gfx::Matrix4x4& matrix)
 {
   bool is3D = !matrix.Is2D();
 
   nsAutoString resultString(NS_LITERAL_STRING("matrix"));
   if (is3D) {
     resultString.AppendLiteral("3d");
   }
@@ -1407,237 +1407,237 @@ nsComputedDOMStyle::MatrixToCSSValue(con
     resultString.AppendLiteral(", ");
     resultString.AppendFloat(matrix._43);
     resultString.AppendLiteral(", ");
     resultString.AppendFloat(matrix._44);
   }
   resultString.Append(')');
 
   /* Create a value to hold our result. */
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   val->SetString(resultString);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetCounterReset()
 {
   const nsStyleContent *content = StyleContent();
 
   if (content->CounterResetCount() == 0) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
-  }
-
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   for (uint32_t i = 0, i_end = content->CounterResetCount(); i < i_end; ++i) {
     RefPtr<nsROCSSPrimitiveValue> name = new nsROCSSPrimitiveValue;
     RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
 
     const nsStyleCounterData *data = content->GetCounterResetAt(i);
     nsAutoString escaped;
     nsStyleUtil::AppendEscapedCSSIdent(data->mCounter, escaped);
     name->SetString(escaped);
     value->SetNumber(data->mValue); // XXX This should really be integer
 
     valueList->AppendCSSValue(name.forget());
     valueList->AppendCSSValue(value.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetQuotes()
 {
   const nsStyleQuotes *quotes = StyleQuotes();
 
   if (quotes->QuotesCount() == 0) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
-  }
-
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   for (uint32_t i = 0, i_end = quotes->QuotesCount(); i < i_end; ++i) {
     RefPtr<nsROCSSPrimitiveValue> openVal = new nsROCSSPrimitiveValue;
     RefPtr<nsROCSSPrimitiveValue> closeVal = new nsROCSSPrimitiveValue;
 
     nsString s;
     nsStyleUtil::AppendEscapedCSSString(*quotes->OpenQuoteAt(i), s);
     openVal->SetString(s);
     s.Truncate();
     nsStyleUtil::AppendEscapedCSSString(*quotes->CloseQuoteAt(i), s);
     closeVal->SetString(s);
 
     valueList->AppendCSSValue(openVal.forget());
     valueList->AppendCSSValue(closeVal.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontFamily()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleFont* font = StyleFont();
   nsAutoString fontlistStr;
   nsStyleUtil::AppendEscapedCSSFontFamilyList(font->mFont.fontlist,
                                               fontlistStr);
   val->SetString(fontlistStr);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontSize()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   // Note: StyleFont()->mSize is the 'computed size';
   // StyleFont()->mFont.size is the 'actual size'
   val->SetAppUnits(StyleFont()->mSize);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontSizeAdjust()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleFont *font = StyleFont();
 
   if (font->mFont.sizeAdjust >= 0.0f) {
     val->SetNumber(font->mFont.sizeAdjust);
   } else {
     val->SetIdent(eCSSKeyword_none);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOsxFontSmoothing()
 {
   if (nsContentUtils::ShouldResistFingerprinting(
         mPresShell->GetPresContext()->GetDocShell()))
     return nullptr;
 
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.smoothing,
                                                nsCSSProps::kFontSmoothingKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontStretch()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.stretch,
                                                nsCSSProps::kFontStretchKTable));
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontStyle()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.style,
                                                nsCSSProps::kFontStyleKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontWeight()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleFont* font = StyleFont();
 
   uint16_t weight = font->mFont.weight;
   NS_ASSERTION(weight % 100 == 0, "unexpected value of font-weight");
   val->SetNumber(weight);
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontFeatureSettings()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleFont* font = StyleFont();
   if (font->mFont.fontFeatureSettings.IsEmpty()) {
     val->SetIdent(eCSSKeyword_normal);
   } else {
     nsAutoString result;
     nsStyleUtil::AppendFontFeatureSettings(font->mFont.fontFeatureSettings,
                                            result);
     val->SetString(result);
   }
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontKerning()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.kerning,
                                    nsCSSProps::kFontKerningKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontLanguageOverride()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleFont* font = StyleFont();
   if (font->mFont.languageOverride.IsEmpty()) {
     val->SetIdent(eCSSKeyword_normal);
   } else {
     nsString str;
     nsStyleUtil::AppendEscapedCSSString(font->mFont.languageOverride, str);
     val->SetString(str);
   }
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontSynthesis()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t intValue = StyleFont()->mFont.synthesis;
 
   if (0 == intValue) {
     val->SetIdent(eCSSKeyword_none);
   } else {
     nsAutoString valueStr;
 
     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_synthesis,
       intValue, NS_FONT_SYNTHESIS_WEIGHT,
       NS_FONT_SYNTHESIS_STYLE, valueStr);
     val->SetString(valueStr);
   }
 
-  return val;
+  return val.forget();
 }
 
 // return a value *only* for valid longhand values from CSS 2.1, either
 // normal or small-caps only
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontVariant()
 {
   const nsFont& f = StyleFont()->mFont;
 
   // if any of the other font-variant subproperties other than
   // font-variant-caps are not normal then can't calculate a computed value
   if (f.variantAlternates || f.variantEastAsian || f.variantLigatures ||
       f.variantNumeric || f.variantPosition) {
@@ -1651,31 +1651,31 @@ nsComputedDOMStyle::DoGetFontVariant()
       break;
     case NS_FONT_VARIANT_CAPS_SMALLCAPS:
       keyword = eCSSKeyword_small_caps;
       break;
     default:
       return nullptr;
   }
 
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(keyword);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontVariantAlternates()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t intValue = StyleFont()->mFont.variantAlternates;
 
   if (0 == intValue) {
     val->SetIdent(eCSSKeyword_normal);
-    return val;
+    return val.forget();
   }
 
   // first, include enumerated values
   nsAutoString valueStr;
 
   nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_alternates,
     intValue & NS_FONT_VARIANT_ALTERNATES_ENUMERATED_MASK,
     NS_FONT_VARIANT_ALTERNATES_HISTORICAL,
@@ -1683,161 +1683,161 @@ nsComputedDOMStyle::DoGetFontVariantAlte
 
   // next, include functional values if present
   if (intValue & NS_FONT_VARIANT_ALTERNATES_FUNCTIONAL_MASK) {
     nsStyleUtil::SerializeFunctionalAlternates(StyleFont()->mFont.alternateValues,
                                                valueStr);
   }
 
   val->SetString(valueStr);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontVariantCaps()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t intValue = StyleFont()->mFont.variantCaps;
 
   if (0 == intValue) {
     val->SetIdent(eCSSKeyword_normal);
   } else {
     val->SetIdent(
       nsCSSProps::ValueToKeywordEnum(intValue,
                                      nsCSSProps::kFontVariantCapsKTable));
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontVariantEastAsian()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t intValue = StyleFont()->mFont.variantEastAsian;
 
   if (0 == intValue) {
     val->SetIdent(eCSSKeyword_normal);
   } else {
     nsAutoString valueStr;
 
     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_east_asian,
       intValue, NS_FONT_VARIANT_EAST_ASIAN_JIS78,
       NS_FONT_VARIANT_EAST_ASIAN_RUBY, valueStr);
     val->SetString(valueStr);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontVariantLigatures()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t intValue = StyleFont()->mFont.variantLigatures;
 
   if (0 == intValue) {
     val->SetIdent(eCSSKeyword_normal);
   } else if (NS_FONT_VARIANT_LIGATURES_NONE == intValue) {
     val->SetIdent(eCSSKeyword_none);
   } else {
     nsAutoString valueStr;
 
     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_ligatures,
       intValue, NS_FONT_VARIANT_LIGATURES_NONE,
       NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL, valueStr);
     val->SetString(valueStr);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontVariantNumeric()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t intValue = StyleFont()->mFont.variantNumeric;
 
   if (0 == intValue) {
     val->SetIdent(eCSSKeyword_normal);
   } else {
     nsAutoString valueStr;
 
     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_font_variant_numeric,
       intValue, NS_FONT_VARIANT_NUMERIC_LINING,
       NS_FONT_VARIANT_NUMERIC_ORDINAL, valueStr);
     val->SetString(valueStr);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontVariantPosition()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t intValue = StyleFont()->mFont.variantPosition;
 
   if (0 == intValue) {
     val->SetIdent(eCSSKeyword_normal);
   } else {
     val->SetIdent(
       nsCSSProps::ValueToKeywordEnum(intValue,
                                      nsCSSProps::kFontVariantPositionKTable));
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetBackgroundList(uint8_t nsStyleBackground::Layer::* aMember,
                                       uint32_t nsStyleBackground::* aCount,
                                       const KTableEntry aTable[])
 {
   const nsStyleBackground* bg = StyleBackground();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   for (uint32_t i = 0, i_end = bg->*aCount; i < i_end; ++i) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(nsCSSProps::ValueToKeywordEnum(bg->mLayers[i].*aMember,
                                                  aTable));
     valueList->AppendCSSValue(val.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundAttachment()
 {
   return GetBackgroundList(&nsStyleBackground::Layer::mAttachment,
                            &nsStyleBackground::mAttachmentCount,
                            nsCSSProps::kBackgroundAttachmentKTable);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundClip()
 {
   return GetBackgroundList(&nsStyleBackground::Layer::mClip,
                            &nsStyleBackground::mClipCount,
                            nsCSSProps::kBackgroundOriginKTable);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundColor()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleBackground()->mBackgroundColor);
-  return val;
+  return val.forget();
 }
 
 
 static void
 SetValueToCalc(const nsStyleCoord::CalcValue *aCalc, nsROCSSPrimitiveValue *aValue)
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString tmp, result;
@@ -2114,43 +2114,43 @@ nsComputedDOMStyle::SetValueToStyleImage
       aValue->SetIdent(eCSSKeyword_none);
       break;
     default:
       NS_NOTREACHED("unexpected image type");
       break;
   }
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundImage()
 {
   const nsStyleBackground* bg = StyleBackground();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   for (uint32_t i = 0, i_end = bg->mImageCount; i < i_end; ++i) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
     const nsStyleImage& image = bg->mLayers[i].mImage;
     SetValueToStyleImage(image, val);
     valueList->AppendCSSValue(val.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundBlendMode()
 {
   return GetBackgroundList(&nsStyleBackground::Layer::mBlendMode,
                            &nsStyleBackground::mBlendModeCount,
                            nsCSSProps::kBlendModeKTable);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundOrigin()
 {
   return GetBackgroundList(&nsStyleBackground::Layer::mOrigin,
                            &nsStyleBackground::mOriginCount,
                            nsCSSProps::kBackgroundOriginKTable);
 }
 
 void
@@ -2178,38 +2178,38 @@ nsComputedDOMStyle::SetValueToPosition(
   SetValueToPositionCoord(aPosition.mXPosition, valX);
   aValueList->AppendCSSValue(valX.forget());
 
   RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
   SetValueToPositionCoord(aPosition.mYPosition, valY);
   aValueList->AppendCSSValue(valY.forget());
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundPosition()
 {
   const nsStyleBackground* bg = StyleBackground();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   for (uint32_t i = 0, i_end = bg->mPositionCount; i < i_end; ++i) {
     RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
     SetValueToPosition(bg->mLayers[i].mPosition, itemList);
     valueList->AppendCSSValue(itemList.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundRepeat()
 {
   const nsStyleBackground* bg = StyleBackground();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   for (uint32_t i = 0, i_end = bg->mRepeatCount; i < i_end; ++i) {
     RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
     RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
 
     const uint8_t& xRepeat = bg->mLayers[i].mRepeat.mXRepeat;
     const uint8_t& yRepeat = bg->mLayers[i].mRepeat.mYRepeat;
 
@@ -2241,25 +2241,25 @@ nsComputedDOMStyle::DoGetBackgroundRepea
     }
     itemList->AppendCSSValue(valX.forget());
     if (valY) {
       itemList->AppendCSSValue(valY.forget());
     }
     valueList->AppendCSSValue(itemList.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundSize()
 {
   const nsStyleBackground* bg = StyleBackground();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   for (uint32_t i = 0, i_end = bg->mSizeCount; i < i_end; ++i) {
     const nsStyleBackground::Size &size = bg->mLayers[i].mSize;
 
     switch (size.mWidthType) {
       case nsStyleBackground::Size::eContain:
       case nsStyleBackground::Size::eCover: {
         MOZ_ASSERT(size.mWidthType == size.mHeightType,
@@ -2322,41 +2322,41 @@ nsComputedDOMStyle::DoGetBackgroundSize(
         itemList->AppendCSSValue(valX.forget());
         itemList->AppendCSSValue(valY.forget());
         valueList->AppendCSSValue(itemList.forget());
         break;
       }
     }
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridTemplateAreas()
 {
   const css::GridTemplateAreasValue* areas =
     StylePosition()->mGridTemplateAreas;
   if (!areas) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
+    return val.forget();
   }
 
   MOZ_ASSERT(!areas->mTemplates.IsEmpty(),
              "Unexpected empty array in GridTemplateAreasValue");
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   for (uint32_t i = 0; i < areas->mTemplates.Length(); i++) {
     nsAutoString str;
     nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[i], str);
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetString(str);
     valueList->AppendCSSValue(val.forget());
   }
-  return valueList;
+  return valueList.forget();
 }
 
 void
 nsComputedDOMStyle::AppendGridLineNames(nsString& aResult,
                                         const nsTArray<nsString>& aLineNames)
 {
   MOZ_ASSERT(!aLineNames.IsEmpty(), "expected some line names");
   uint32_t numLines = aLineNames.Length();
@@ -2405,28 +2405,28 @@ nsComputedDOMStyle::AppendGridLineNames(
     }
     AppendGridLineNames(lineNamesString, aLineNames2);
   }
   lineNamesString.Append(']');
   val->SetString(lineNamesString);
   aValueList->AppendCSSValue(val.forget());
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue,
                                      const nsStyleCoord& aMaxValue)
 {
   if (aMinValue == aMaxValue) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     SetValueToCoord(val, aMinValue, true,
                     nullptr, nsCSSProps::kGridTrackBreadthKTable);
-    return val;
-  }
-
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    return val.forget();
+  }
+
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString argumentStr, minmaxStr;
   minmaxStr.AppendLiteral("minmax(");
 
   SetValueToCoord(val, aMinValue, true,
                   nullptr, nsCSSProps::kGridTrackBreadthKTable);
   val->GetCssText(argumentStr);
   minmaxStr.Append(argumentStr);
 
@@ -2434,29 +2434,29 @@ nsComputedDOMStyle::GetGridTrackSize(con
 
   SetValueToCoord(val, aMaxValue, true,
                   nullptr, nsCSSProps::kGridTrackBreadthKTable);
   val->GetCssText(argumentStr);
   minmaxStr.Append(argumentStr);
 
   minmaxStr.Append(char16_t(')'));
   val->SetString(minmaxStr);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetGridTemplateColumnsRows(const nsStyleGridTemplate& aTrackList,
                                                const nsTArray<nscoord>* aTrackSizes)
 {
   if (aTrackList.mIsSubgrid) {
     // XXX TODO: add support for repeat(auto-fill) for 'subgrid' (bug 1234311)
     NS_ASSERTION(aTrackList.mMinTrackSizingFunctions.IsEmpty() &&
                  aTrackList.mMaxTrackSizingFunctions.IsEmpty(),
                  "Unexpected sizing functions with subgrid");
-    nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+    RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
     RefPtr<nsROCSSPrimitiveValue> subgridKeyword = new nsROCSSPrimitiveValue;
     subgridKeyword->SetIdent(eCSSKeyword_subgrid);
     valueList->AppendCSSValue(subgridKeyword.forget());
 
     for (uint32_t i = 0; i < aTrackList.mLineNameLists.Length(); i++) {
       if (MOZ_UNLIKELY(aTrackList.IsRepeatAutoIndex(i))) {
         MOZ_ASSERT(aTrackList.mIsAutoFill, "subgrid can only have 'auto-fill'");
@@ -2469,48 +2469,48 @@ nsComputedDOMStyle::GetGridTemplateColum
         valueList->AppendCSSValue(start.forget());
         AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListBefore);
         RefPtr<nsROCSSPrimitiveValue> end = new nsROCSSPrimitiveValue;
         end->SetString(NS_LITERAL_STRING(")"));
         valueList->AppendCSSValue(end.forget());
       }
       AppendGridLineNames(valueList, aTrackList.mLineNameLists[i]);
     }
-    return valueList;
+    return valueList.forget();
   }
 
   uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length();
   MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes,
              "Different number of min and max track sizing functions");
   // An empty <track-list> is represented as "none" in syntax.
   if (numSizes == 0) {
-    nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
-  }
-
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   // Delimiting N tracks requires N+1 lines:
   // one before each track, plus one at the very end.
   MOZ_ASSERT(aTrackList.mLineNameLists.Length() == numSizes + 1,
              "Unexpected number of line name lists");
   if (aTrackSizes) {
     // We've done layout on the grid and have resolved the sizes of its tracks,
     // so we'll return those sizes here.  The grid spec says we MAY use
     // repeat(<positive-integer>, Npx) here for consecutive tracks with the same
     // size, but that doesn't seem worth doing since even for repeat(auto-*)
     // the resolved size might differ for the repeated tracks.
     const uint32_t numTracks = aTrackSizes->Length();
     MOZ_ASSERT(numTracks > 0 ||
                (aTrackList.HasRepeatAuto() && !aTrackList.mIsAutoFill),
                "only 'auto-fit' can result in zero tracks");
     if (numTracks == 0) {
-      nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+      RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
       val->SetIdent(eCSSKeyword_none);
-      return val;
+      return val.forget();
     }
     int32_t endOfRepeat = 0;  // first index after any repeat() tracks
     int32_t offsetToLastRepeat = 0;
     if (aTrackList.HasRepeatAuto()) {
       // offsetToLastRepeat is -1 if all repeat(auto-fit) tracks are empty
       offsetToLastRepeat = numTracks + 1 - aTrackList.mLineNameLists.Length();
       endOfRepeat = aTrackList.mRepeatAutoIndex + offsetToLastRepeat + 1;
     }
@@ -2569,113 +2569,104 @@ nsComputedDOMStyle::GetGridTemplateColum
         RefPtr<nsROCSSPrimitiveValue> start = new nsROCSSPrimitiveValue;
         start->SetString(aTrackList.mIsAutoFill ? NS_LITERAL_STRING("repeat(auto-fill,")
                                                 : NS_LITERAL_STRING("repeat(auto-fit,"));
         valueList->AppendCSSValue(start.forget());
         if (!aTrackList.mRepeatAutoLineNameListBefore.IsEmpty()) {
           AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListBefore);
         }
 
-        // XXXdholbert The |tmpTrackSize| RefPtr variable below can go away once
-        // we fix bug 1234676 and can make GetGridTrackSize return an
-        // already_AddRefed value.
-        RefPtr<CSSValue> tmpTrackSize =
+        valueList->AppendCSSValue(
           GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
-                           aTrackList.mMaxTrackSizingFunctions[i]);
-
-        valueList->AppendCSSValue(tmpTrackSize.forget());
+                           aTrackList.mMaxTrackSizingFunctions[i]));
         if (!aTrackList.mRepeatAutoLineNameListAfter.IsEmpty()) {
           AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListAfter);
         }
         RefPtr<nsROCSSPrimitiveValue> end = new nsROCSSPrimitiveValue;
         end->SetString(NS_LITERAL_STRING(")"));
         valueList->AppendCSSValue(end.forget());
       } else {
-        // XXXdholbert The |tmpTrackSize| RefPtr variable below can go away once
-        // we fix bug 1234676 and make GetGridTrackSize return an
-        // already_AddRefed value.
-        RefPtr<CSSValue> tmpTrackSize =
+        valueList->AppendCSSValue(
           GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
-                           aTrackList.mMaxTrackSizingFunctions[i]);
-        valueList->AppendCSSValue(tmpTrackSize.forget());
+                           aTrackList.mMaxTrackSizingFunctions[i]));
       }
     }
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridAutoFlow()
 {
   nsAutoString str;
   nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_grid_auto_flow,
                                      StylePosition()->mGridAutoFlow,
                                      NS_STYLE_GRID_AUTO_FLOW_ROW,
                                      NS_STYLE_GRID_AUTO_FLOW_DENSE,
                                      str);
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetString(str);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridAutoColumns()
 {
   return GetGridTrackSize(StylePosition()->mGridAutoColumnsMin,
                           StylePosition()->mGridAutoColumnsMax);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridAutoRows()
 {
   return GetGridTrackSize(StylePosition()->mGridAutoRowsMin,
                           StylePosition()->mGridAutoRowsMax);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridTemplateColumns()
 {
   const nsTArray<nscoord>* trackSizes = nullptr;
   if (mInnerFrame) {
     nsIFrame* gridContainerCandidate = mInnerFrame->GetContentInsertionFrame();
     if (gridContainerCandidate &&
         gridContainerCandidate->GetType() == nsGkAtoms::gridContainerFrame) {
       auto gridContainer = static_cast<nsGridContainerFrame*>(gridContainerCandidate);
       trackSizes = gridContainer->GetComputedTemplateColumns();
     }
   }
   return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateColumns, trackSizes);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridTemplateRows()
 {
   const nsTArray<nscoord>* trackSizes = nullptr;
   if (mInnerFrame) {
     nsIFrame* gridContainerCandidate = mInnerFrame->GetContentInsertionFrame();
     if (gridContainerCandidate &&
         gridContainerCandidate->GetType() == nsGkAtoms::gridContainerFrame) {
       auto gridContainer = static_cast<nsGridContainerFrame*>(gridContainerCandidate);
       trackSizes = gridContainer->GetComputedTemplateRows();
     }
   }
   return GetGridTemplateColumnsRows(StylePosition()->mGridTemplateRows, trackSizes);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetGridLine(const nsStyleGridLine& aGridLine)
 {
   if (aGridLine.IsAuto()) {
-    nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_auto);
-    return val;
-  }
-
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   if (aGridLine.mHasSpan) {
     RefPtr<nsROCSSPrimitiveValue> span = new nsROCSSPrimitiveValue;
     span->SetIdent(eCSSKeyword_span);
     valueList->AppendCSSValue(span.forget());
   }
 
   if (aGridLine.mInteger != 0) {
@@ -2689,416 +2680,416 @@ nsComputedDOMStyle::GetGridLine(const ns
     nsString escapedLineName;
     nsStyleUtil::AppendEscapedCSSIdent(aGridLine.mLineName, escapedLineName);
     lineName->SetString(escapedLineName);
     valueList->AppendCSSValue(lineName.forget());
   }
 
   NS_ASSERTION(valueList->Length() > 0,
                "Should have appended at least one value");
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridColumnStart()
 {
   return GetGridLine(StylePosition()->mGridColumnStart);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridColumnEnd()
 {
   return GetGridLine(StylePosition()->mGridColumnEnd);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridRowStart()
 {
   return GetGridLine(StylePosition()->mGridRowStart);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridRowEnd()
 {
   return GetGridLine(StylePosition()->mGridRowEnd);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridColumnGap()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetAppUnits(StylePosition()->mGridColumnGap);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetGridRowGap()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetAppUnits(StylePosition()->mGridRowGap);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPaddingTop()
 {
   return GetPaddingWidthFor(NS_SIDE_TOP);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPaddingBottom()
 {
   return GetPaddingWidthFor(NS_SIDE_BOTTOM);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPaddingLeft()
 {
   return GetPaddingWidthFor(NS_SIDE_LEFT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPaddingRight()
 {
   return GetPaddingWidthFor(NS_SIDE_RIGHT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderCollapse()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mBorderCollapse,
                                    nsCSSProps::kBorderCollapseKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderSpacing()
 {
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   RefPtr<nsROCSSPrimitiveValue> xSpacing = new nsROCSSPrimitiveValue;
   RefPtr<nsROCSSPrimitiveValue> ySpacing = new nsROCSSPrimitiveValue;
 
   const nsStyleTableBorder *border = StyleTableBorder();
   xSpacing->SetAppUnits(border->mBorderSpacingCol);
   ySpacing->SetAppUnits(border->mBorderSpacingRow);
 
   valueList->AppendCSSValue(xSpacing.forget());
   valueList->AppendCSSValue(ySpacing.forget());
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetCaptionSide()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mCaptionSide,
                                    nsCSSProps::kCaptionSideKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetEmptyCells()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleTableBorder()->mEmptyCells,
                                    nsCSSProps::kEmptyCellsKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTableLayout()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleTable()->mLayoutStrategy,
                                    nsCSSProps::kTableLayoutKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderTopStyle()
 {
   return GetBorderStyleFor(NS_SIDE_TOP);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderBottomStyle()
 {
   return GetBorderStyleFor(NS_SIDE_BOTTOM);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderLeftStyle()
 {
   return GetBorderStyleFor(NS_SIDE_LEFT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderRightStyle()
 {
   return GetBorderStyleFor(NS_SIDE_RIGHT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderBottomColors()
 {
   return GetBorderColorsFor(NS_SIDE_BOTTOM);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderLeftColors()
 {
   return GetBorderColorsFor(NS_SIDE_LEFT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderRightColors()
 {
   return GetBorderColorsFor(NS_SIDE_RIGHT);
 }
 
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderTopColors()
 {
   return GetBorderColorsFor(NS_SIDE_TOP);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderBottomLeftRadius()
 {
   return GetEllipseRadii(StyleBorder()->mBorderRadius,
                          NS_CORNER_BOTTOM_LEFT, true);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderBottomRightRadius()
 {
   return GetEllipseRadii(StyleBorder()->mBorderRadius,
                          NS_CORNER_BOTTOM_RIGHT, true);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderTopLeftRadius()
 {
   return GetEllipseRadii(StyleBorder()->mBorderRadius,
                          NS_CORNER_TOP_LEFT, true);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderTopRightRadius()
 {
   return GetEllipseRadii(StyleBorder()->mBorderRadius,
                          NS_CORNER_TOP_RIGHT, true);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderTopWidth()
 {
   return GetBorderWidthFor(NS_SIDE_TOP);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderBottomWidth()
 {
   return GetBorderWidthFor(NS_SIDE_BOTTOM);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderLeftWidth()
 {
   return GetBorderWidthFor(NS_SIDE_LEFT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderRightWidth()
 {
   return GetBorderWidthFor(NS_SIDE_RIGHT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderTopColor()
 {
   return GetBorderColorFor(NS_SIDE_TOP);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderBottomColor()
 {
   return GetBorderColorFor(NS_SIDE_BOTTOM);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderLeftColor()
 {
   return GetBorderColorFor(NS_SIDE_LEFT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderRightColor()
 {
   return GetBorderColorFor(NS_SIDE_RIGHT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarginTopWidth()
 {
   return GetMarginWidthFor(NS_SIDE_TOP);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarginBottomWidth()
 {
   return GetMarginWidthFor(NS_SIDE_BOTTOM);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarginLeftWidth()
 {
   return GetMarginWidthFor(NS_SIDE_LEFT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarginRightWidth()
 {
   return GetMarginWidthFor(NS_SIDE_RIGHT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarkerOffset()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StyleContent()->mMarkerOffset, false);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOrient()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOrient,
                                    nsCSSProps::kOrientKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetScrollBehavior()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollBehavior,
                                    nsCSSProps::kScrollBehaviorKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetScrollSnapType()
 {
   const nsStyleDisplay* display = StyleDisplay();
   if (display->mScrollSnapTypeX != display->mScrollSnapTypeY) {
     // No value to return.  We can't express this combination of
     // values as a shorthand.
     return nullptr;
   }
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollSnapTypeX,
                                    nsCSSProps::kScrollSnapTypeKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetScrollSnapTypeX()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollSnapTypeX,
                                    nsCSSProps::kScrollSnapTypeKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetScrollSnapTypeY()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mScrollSnapTypeY,
                                    nsCSSProps::kScrollSnapTypeKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetScrollSnapPoints(const nsStyleCoord& aCoord)
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   if (aCoord.GetUnit() == eStyleUnit_None) {
     val->SetIdent(eCSSKeyword_none);
   } else {
     nsAutoString argumentString;
     SetCssTextToCoord(argumentString, aCoord);
     nsAutoString tmp;
     tmp.AppendLiteral("repeat(");
     tmp.Append(argumentString);
     tmp.Append(')');
     val->SetString(tmp);
   }
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetScrollSnapPointsX()
 {
   return GetScrollSnapPoints(StyleDisplay()->mScrollSnapPointsX);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetScrollSnapPointsY()
 {
   return GetScrollSnapPoints(StyleDisplay()->mScrollSnapPointsY);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetScrollSnapDestination()
 {
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   SetValueToPosition(StyleDisplay()->mScrollSnapDestination, valueList);
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetScrollSnapCoordinate()
 {
   const nsStyleDisplay* sd = StyleDisplay();
   if (sd->mScrollSnapCoordinate.IsEmpty()) {
     // Having no snap coordinates is interpreted as "none"
-    nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
+    return val.forget();
   } else {
-    nsDOMCSSValueList* valueList = GetROCSSValueList(true);
+    RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
     for (size_t i = 0, i_end = sd->mScrollSnapCoordinate.Length(); i < i_end; ++i) {
       RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
       SetValueToPosition(sd->mScrollSnapCoordinate[i], itemList);
       valueList->AppendCSSValue(itemList.forget());
     }
-    return valueList;
-  }
-}
-
-CSSValue*
+    return valueList.forget();
+  }
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOutlineWidth()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleOutline* outline = StyleOutline();
 
   nscoord width;
   if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) {
     NS_ASSERTION(outline->GetOutlineWidth(width) && width == 0,
                  "unexpected width");
     width = 0;
@@ -3106,79 +3097,79 @@ nsComputedDOMStyle::DoGetOutlineWidth()
 #ifdef DEBUG
     bool res =
 #endif
       outline->GetOutlineWidth(width);
     NS_ASSERTION(res, "percent outline doesn't exist");
   }
   val->SetAppUnits(width);
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOutlineStyle()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleOutline()->GetOutlineStyle(),
                                    nsCSSProps::kOutlineStyleKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOutlineOffset()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetAppUnits(StyleOutline()->mOutlineOffset);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOutlineRadiusBottomLeft()
 {
   return GetEllipseRadii(StyleOutline()->mOutlineRadius,
                          NS_CORNER_BOTTOM_LEFT, false);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOutlineRadiusBottomRight()
 {
   return GetEllipseRadii(StyleOutline()->mOutlineRadius,
                          NS_CORNER_BOTTOM_RIGHT, false);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOutlineRadiusTopLeft()
 {
   return GetEllipseRadii(StyleOutline()->mOutlineRadius,
                          NS_CORNER_TOP_LEFT, false);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOutlineRadiusTopRight()
 {
   return GetEllipseRadii(StyleOutline()->mOutlineRadius,
                          NS_CORNER_TOP_RIGHT, false);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOutlineColor()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   nscolor color;
   if (!StyleOutline()->GetOutlineColor(color))
     color = StyleColor()->mColor;
 
   SetToRGBAColor(val, color);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetEllipseRadii(const nsStyleCorners& aRadius,
                                     uint8_t aFullCorner,
                                     bool aIsBorder) // else outline
 {
   nsStyleCoord radiusX, radiusY;
   if (mInnerFrame && aIsBorder) {
     nscoord radii[8];
     mInnerFrame->GetBorderRadii(radii);
@@ -3202,46 +3193,46 @@ nsComputedDOMStyle::GetEllipseRadii(cons
                               &nsComputedDOMStyle::GetFrameBorderRectHeight,
                               0, true);
       radiusY.SetCoordValue(v);
     }
   }
 
   // for compatibility, return a single value if X and Y are equal
   if (radiusX == radiusY) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
     SetValueToCoord(val, radiusX, true);
 
-    return val;
-  }
-
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
   RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
 
   SetValueToCoord(valX, radiusX, true);
   SetValueToCoord(valY, radiusY, true);
 
   valueList->AppendCSSValue(valX.forget());
   valueList->AppendCSSValue(valY.forget());
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray,
                                       const nscolor& aDefaultColor,
                                       bool aIsBoxShadow)
 {
   if (!aArray) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
+    return val.forget();
   }
 
   static nscoord nsCSSShadowItem::* const shadowValuesNoSpread[] = {
     &nsCSSShadowItem::mXOffset,
     &nsCSSShadowItem::mYOffset,
     &nsCSSShadowItem::mRadius
   };
 
@@ -3257,17 +3248,17 @@ nsComputedDOMStyle::GetCSSShadowArray(ns
   if (aIsBoxShadow) {
     shadowValues = shadowValuesWithSpread;
     shadowValuesLength = ArrayLength(shadowValuesWithSpread);
   } else {
     shadowValues = shadowValuesNoSpread;
     shadowValuesLength = ArrayLength(shadowValuesNoSpread);
   }
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   for (nsCSSShadowItem *item = aArray->ShadowAt(0),
                    *item_end = item + aArray->Length();
        item < item_end; ++item) {
     RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
 
     // Color is either the specified shadow color or the foreground color
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
@@ -3293,79 +3284,79 @@ nsComputedDOMStyle::GetCSSShadowArray(ns
       val->SetIdent(
         nsCSSProps::ValueToKeywordEnum(NS_STYLE_BOX_SHADOW_INSET,
                                        nsCSSProps::kBoxShadowTypeKTable));
       itemList->AppendCSSValue(val.forget());
     }
     valueList->AppendCSSValue(itemList.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxDecorationBreak()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleBorder()->mBoxDecorationBreak,
                                    nsCSSProps::kBoxDecorationBreakKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxShadow()
 {
   return GetCSSShadowArray(StyleBorder()->mBoxShadow,
                            StyleColor()->mColor,
                            true);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetZIndex()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StylePosition()->mZIndex, false);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetListStyleImage()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleList* list = StyleList();
 
   if (!list->GetListStyleImage()) {
     val->SetIdent(eCSSKeyword_none);
   } else {
     nsCOMPtr<nsIURI> uri;
     if (list->GetListStyleImage()) {
       list->GetListStyleImage()->GetURI(getter_AddRefs(uri));
     }
     val->SetURI(uri);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetListStylePosition()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleList()->mListStylePosition,
                                    nsCSSProps::kListStylePositionKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetListStyleType()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   CounterStyle* style = StyleList()->GetCounterStyle();
   AnonymousCounterStyle* anonymous = style->AsAnonymous();
   nsString tmp;
   if (!anonymous) {
     // want SetIdent
     nsString type;
     StyleList()->GetListStyleType(type);
     nsStyleUtil::AppendEscapedCSSIdent(type, tmp);
@@ -3394,23 +3385,23 @@ nsComputedDOMStyle::DoGetListStyleType()
                  "No symbols in the anonymous counter style");
     for (size_t i = 0, iend = symbols.Length(); i < iend; i++) {
       nsStyleUtil::AppendEscapedCSSString(symbols[i], tmp);
       tmp.Append(' ');
     }
     tmp.Replace(tmp.Length() - 1, 1, char16_t(')'));
   }
   val->SetString(tmp);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetImageRegion()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleList* list = StyleList();
 
   if (list->mImageRegion.width <= 0 || list->mImageRegion.height <= 0) {
     val->SetIdent(eCSSKeyword_auto);
   } else {
     // create the cssvalues for the sides, stick them in the rect object
     nsROCSSPrimitiveValue *topVal    = new nsROCSSPrimitiveValue;
@@ -3421,180 +3412,168 @@ nsComputedDOMStyle::DoGetImageRegion()
                                               bottomVal, leftVal);
     topVal->SetAppUnits(list->mImageRegion.y);
     rightVal->SetAppUnits(list->mImageRegion.width + list->mImageRegion.x);
     bottomVal->SetAppUnits(list->mImageRegion.height + list->mImageRegion.y);
     leftVal->SetAppUnits(list->mImageRegion.x);
     val->SetRect(domRect);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetLineHeight()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   nscoord lineHeight;
   if (GetLineHeightCoord(lineHeight)) {
     val->SetAppUnits(lineHeight);
   } else {
     SetValueToCoord(val, StyleText()->mLineHeight, true,
                     nullptr, nsCSSProps::kLineHeightKTable);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetRubyAlign()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(
     StyleText()->mRubyAlign, nsCSSProps::kRubyAlignKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetRubyPosition()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(
     StyleText()->mRubyPosition, nsCSSProps::kRubyPositionKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetVerticalAlign()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StyleTextReset()->mVerticalAlign, false,
                   &nsComputedDOMStyle::GetLineHeightCoord,
                   nsCSSProps::kVerticalAlignKTable);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::CreateTextAlignValue(uint8_t aAlign, bool aAlignTrue,
                                          const KTableEntry aTable[])
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(aAlign, aTable));
   if (!aAlignTrue) {
-    return val;
-  }
-
-  // XXXdholbert Really we should store |val| in a RefPtr right away, and our
-  // return-type should be already_AddRefed. See bug 1234676.  For now, we only
-  // put it in a RefPtr (for the benefit of AppendCSSValue) after we know we're
-  // not returning it directly.
-  RefPtr<nsROCSSPrimitiveValue> refcountedVal = val;
-  val = nullptr; // (to avoid accidental reuse/misuse)
+    return val.forget();
+  }
 
   RefPtr<nsROCSSPrimitiveValue> first = new nsROCSSPrimitiveValue;
   first->SetIdent(eCSSKeyword_true);
 
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   valueList->AppendCSSValue(first.forget());
-  valueList->AppendCSSValue(refcountedVal.forget());
-  return valueList;
-}
-
-CSSValue*
+  valueList->AppendCSSValue(val.forget());
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextAlign()
 {
   const nsStyleText* style = StyleText();
   return CreateTextAlignValue(style->mTextAlign, style->mTextAlignTrue,
                               nsCSSProps::kTextAlignKTable);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextAlignLast()
 {
   const nsStyleText* style = StyleText();
   return CreateTextAlignValue(style->mTextAlignLast, style->mTextAlignLastTrue,
                               nsCSSProps::kTextAlignLastKTable);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextCombineUpright()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   uint8_t tch = StyleText()->mTextCombineUpright;
 
   if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
     val->SetIdent(
       nsCSSProps::ValueToKeywordEnum(tch,
                                      nsCSSProps::kTextCombineUprightKTable));
   } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) {
     val->SetString(NS_LITERAL_STRING("digits 2"));
   } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3) {
     val->SetString(NS_LITERAL_STRING("digits 3"));
   } else {
     val->SetString(NS_LITERAL_STRING("digits 4"));
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextDecoration()
 {
   const nsStyleTextReset* textReset = StyleTextReset();
 
   bool isInitialStyle =
     textReset->GetDecorationStyle() == NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
   nscolor color;
   bool isForegroundColor;
   textReset->GetDecorationColor(color, isForegroundColor);
 
   if (isInitialStyle && isForegroundColor) {
     return DoGetTextDecorationLine();
   }
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
-
-  // XXXdholbert The |tmp| RefPtr variable below can go away once we fix bug
-  // 1234676 and make the DoGet* functions return an already_AddRefed value.
-  RefPtr<CSSValue> tmp = DoGetTextDecorationLine();
-  valueList->AppendCSSValue(tmp.forget());
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+
+  valueList->AppendCSSValue(DoGetTextDecorationLine());
   if (!isInitialStyle) {
-    tmp = DoGetTextDecorationStyle();
-    valueList->AppendCSSValue(tmp.forget());
+    valueList->AppendCSSValue(DoGetTextDecorationStyle());
   }
   if (!isForegroundColor) {
-    tmp = DoGetTextDecorationColor();
-    valueList->AppendCSSValue(tmp.forget());
-  }
-
-  return valueList;
-}
-
-CSSValue*
+    valueList->AppendCSSValue(DoGetTextDecorationColor());
+  }
+
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextDecorationColor()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   nscolor color;
   bool isForeground;
   StyleTextReset()->GetDecorationColor(color, isForeground);
   if (isForeground) {
     color = StyleColor()->mColor;
   }
 
   SetToRGBAColor(val, color);
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextDecorationLine()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t intValue = StyleTextReset()->mTextDecorationLine;
 
   if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
     val->SetIdent(eCSSKeyword_none);
   } else {
     nsAutoString decorationLineString;
     // Clear the -moz-anchor-decoration bit and the OVERRIDE_ALL bits -- we
@@ -3602,81 +3581,81 @@ nsComputedDOMStyle::DoGetTextDecorationL
     intValue &= ~(NS_STYLE_TEXT_DECORATION_LINE_PREF_ANCHORS |
                   NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL);
     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_text_decoration_line,
       intValue, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
       NS_STYLE_TEXT_DECORATION_LINE_BLINK, decorationLineString);
     val->SetString(decorationLineString);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextDecorationStyle()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleTextReset()->GetDecorationStyle(),
                                    nsCSSProps::kTextDecorationStyleKTable));
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextEmphasisColor()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   const nsStyleText* text = StyleText();
   nscolor color = text->mTextEmphasisColorForeground ?
     StyleColor()->mColor : text->mTextEmphasisColor;
   SetToRGBAColor(val, color);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextEmphasisPosition()
 {
   auto position = StyleText()->mTextEmphasisPosition;
 
   MOZ_ASSERT(!(position & NS_STYLE_TEXT_EMPHASIS_POSITION_OVER) !=
              !(position & NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER));
   RefPtr<nsROCSSPrimitiveValue> first = new nsROCSSPrimitiveValue;
   first->SetIdent((position & NS_STYLE_TEXT_EMPHASIS_POSITION_OVER) ?
                   eCSSKeyword_over : eCSSKeyword_under);
 
   MOZ_ASSERT(!(position & NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT) !=
              !(position & NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT));
   RefPtr<nsROCSSPrimitiveValue> second = new nsROCSSPrimitiveValue;
   second->SetIdent((position & NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT) ?
                    eCSSKeyword_left : eCSSKeyword_right);
 
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   valueList->AppendCSSValue(first.forget());
   valueList->AppendCSSValue(second.forget());
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextEmphasisStyle()
 {
   auto style = StyleText()->mTextEmphasisStyle;
   if (style == NS_STYLE_TEXT_EMPHASIS_STYLE_NONE) {
-    nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
+    return val.forget();
   }
   if (style == NS_STYLE_TEXT_EMPHASIS_STYLE_STRING) {
-    nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     nsString tmp;
     nsStyleUtil::AppendEscapedCSSString(
       StyleText()->mTextEmphasisStyleString, tmp);
     val->SetString(tmp);
-    return val;
+    return val.forget();
   }
 
   RefPtr<nsROCSSPrimitiveValue> fillVal = new nsROCSSPrimitiveValue;
   if ((style & NS_STYLE_TEXT_EMPHASIS_STYLE_FILL_MASK) ==
       NS_STYLE_TEXT_EMPHASIS_STYLE_FILLED) {
     fillVal->SetIdent(eCSSKeyword_filled);
   } else {
     MOZ_ASSERT((style & NS_STYLE_TEXT_EMPHASIS_STYLE_FILL_MASK) ==
@@ -3684,253 +3663,253 @@ nsComputedDOMStyle::DoGetTextEmphasisSty
     fillVal->SetIdent(eCSSKeyword_open);
   }
 
   RefPtr<nsROCSSPrimitiveValue> shapeVal = new nsROCSSPrimitiveValue;
   shapeVal->SetIdent(nsCSSProps::ValueToKeywordEnum(
     style & NS_STYLE_TEXT_EMPHASIS_STYLE_SHAPE_MASK,
     nsCSSProps::kTextEmphasisStyleShapeKTable));
 
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   valueList->AppendCSSValue(fillVal.forget());
   valueList->AppendCSSValue(shapeVal.forget());
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextIndent()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StyleText()->mTextIndent, false,
                   &nsComputedDOMStyle::GetCBContentWidth);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextOrientation()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mTextOrientation,
                                    nsCSSProps::kTextOrientationKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextOverflow()
 {
   const nsStyleTextReset *style = StyleTextReset();
   RefPtr<nsROCSSPrimitiveValue> first = new nsROCSSPrimitiveValue;
   const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue();
   if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
     nsString str;
     nsStyleUtil::AppendEscapedCSSString(side->mString, str);
     first->SetString(str);
   } else {
     first->SetIdent(
       nsCSSProps::ValueToKeywordEnum(side->mType,
                                      nsCSSProps::kTextOverflowKTable));
   }
   side = style->mTextOverflow.GetSecondValue();
   if (!side) {
-    return first;
+    return first.forget();
   }
   RefPtr<nsROCSSPrimitiveValue> second = new nsROCSSPrimitiveValue;
   if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
     nsString str;
     nsStyleUtil::AppendEscapedCSSString(side->mString, str);
     second->SetString(str);
   } else {
     second->SetIdent(
       nsCSSProps::ValueToKeywordEnum(side->mType,
                                      nsCSSProps::kTextOverflowKTable));
   }
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   valueList->AppendCSSValue(first.forget());
   valueList->AppendCSSValue(second.forget());
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextShadow()
 {
   return GetCSSShadowArray(StyleText()->mTextShadow,
                            StyleColor()->mColor,
                            false);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextTransform()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleText()->mTextTransform,
                                    nsCSSProps::kTextTransformKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTabSize()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleText()->mTabSize);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetLetterSpacing()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StyleText()->mLetterSpacing, false);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWordSpacing()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StyleText()->mWordSpacing, false);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWhiteSpace()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleText()->mWhiteSpace,
                                    nsCSSProps::kWhitespaceKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWindowDragging()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mWindowDragging,
                                    nsCSSProps::kWindowDraggingKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWindowShadow()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mWindowShadow,
                                    nsCSSProps::kWindowShadowKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWordBreak()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleText()->mWordBreak,
                                    nsCSSProps::kWordBreakKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWordWrap()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleText()->mWordWrap,
                                    nsCSSProps::kWordWrapKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetHyphens()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleText()->mHyphens,
                                    nsCSSProps::kHyphensKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextSizeAdjust()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   switch (StyleText()->mTextSizeAdjust) {
     default:
       NS_NOTREACHED("unexpected value");
       // fall through
     case NS_STYLE_TEXT_SIZE_ADJUST_AUTO:
       val->SetIdent(eCSSKeyword_auto);
       break;
     case NS_STYLE_TEXT_SIZE_ADJUST_NONE:
       val->SetIdent(eCSSKeyword_none);
       break;
   }
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPointerEvents()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mPointerEvents,
                                    nsCSSProps::kPointerEventsKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetVisibility()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mVisible,
                                                nsCSSProps::kVisibilityKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWritingMode()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mWritingMode,
                                    nsCSSProps::kWritingModeKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetDirection()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleVisibility()->mDirection,
                                    nsCSSProps::kDirectionKTable));
-  return val;
+  return val.forget();
 }
 
 static_assert(NS_STYLE_UNICODE_BIDI_NORMAL == 0,
               "unicode-bidi style constants not as expected");
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetUnicodeBidi()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mUnicodeBidi,
                                    nsCSSProps::kUnicodeBidiKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetCursor()
 {
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   const nsStyleUserInterface *ui = StyleUserInterface();
 
   for (nsCursorImage *item = ui->mCursorArray,
          *item_end = ui->mCursorArray + ui->mCursorArrayLength;
        item < item_end; ++item) {
     RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
 
@@ -3953,434 +3932,434 @@ nsComputedDOMStyle::DoGetCursor()
     }
     valueList->AppendCSSValue(itemList.forget());
   }
 
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(ui->mCursor,
                                                nsCSSProps::kCursorKTable));
   valueList->AppendCSSValue(val.forget());
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAppearance()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mAppearance,
                                                nsCSSProps::kAppearanceKTable));
-  return val;
-}
-
-
-CSSValue*
+  return val.forget();
+}
+
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxAlign()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxAlign,
                                                nsCSSProps::kBoxAlignKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxDirection()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxDirection,
                                    nsCSSProps::kBoxDirectionKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxFlex()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleXUL()->mBoxFlex);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxOrdinalGroup()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleXUL()->mBoxOrdinal);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxOrient()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxOrient,
                                    nsCSSProps::kBoxOrientKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxPack()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleXUL()->mBoxPack,
                                                nsCSSProps::kBoxPackKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxSizing()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(uint8_t(StylePosition()->mBoxSizing),
                                    nsCSSProps::kBoxSizingKTable));
-  return val;
+  return val.forget();
 }
 
 /* Border image properties */
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageSource()
 {
   const nsStyleBorder* border = StyleBorder();
 
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   const nsStyleImage& image = border->mBorderImageSource;
   SetValueToStyleImage(image, val);
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageSlice()
 {
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   const nsStyleBorder* border = StyleBorder();
   // Four slice numbers.
   NS_FOR_CSS_SIDES (side) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     SetValueToCoord(val, border->mBorderImageSlice.Get(side), true, nullptr);
     valueList->AppendCSSValue(val.forget());
   }
 
   // Fill keyword.
   if (NS_STYLE_BORDER_IMAGE_SLICE_FILL == border->mBorderImageFill) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_fill);
     valueList->AppendCSSValue(val.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageWidth()
 {
   const nsStyleBorder* border = StyleBorder();
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   NS_FOR_CSS_SIDES (side) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     SetValueToCoord(val, border->mBorderImageWidth.Get(side),
                     true, nullptr);
     valueList->AppendCSSValue(val.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageOutset()
 {
-  nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   const nsStyleBorder* border = StyleBorder();
   // four slice numbers
   NS_FOR_CSS_SIDES (side) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     SetValueToCoord(val, border->mBorderImageOutset.Get(side),
                     true, nullptr);
     valueList->AppendCSSValue(val.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBorderImageRepeat()
 {
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   const nsStyleBorder* border = StyleBorder();
 
   // horizontal repeat
   RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
   valX->SetIdent(
     nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatH,
                                    nsCSSProps::kBorderImageRepeatKTable));
   valueList->AppendCSSValue(valX.forget());
 
   // vertical repeat
   RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
   valY->SetIdent(
     nsCSSProps::ValueToKeywordEnum(border->mBorderImageRepeatV,
                                    nsCSSProps::kBorderImageRepeatKTable));
   valueList->AppendCSSValue(valY.forget());
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFlexBasis()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   // XXXdholbert We could make this more automagic and resolve percentages
   // if we wanted, by passing in a PercentageBaseGetter instead of nullptr
   // below.  Logic would go like this:
   //   if (i'm a flex item) {
   //     if (my flex container is horizontal) {
   //       percentageBaseGetter = &nsComputedDOMStyle::GetCBContentWidth;
   //     } else {
   //       percentageBaseGetter = &nsComputedDOMStyle::GetCBContentHeight;
   //     }
   //   }
 
   SetValueToCoord(val, StylePosition()->mFlexBasis, true,
                   nullptr, nsCSSProps::kWidthKTable);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFlexDirection()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexDirection,
                                    nsCSSProps::kFlexDirectionKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFlexGrow()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StylePosition()->mFlexGrow);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFlexShrink()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StylePosition()->mFlexShrink);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFlexWrap()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StylePosition()->mFlexWrap,
                                    nsCSSProps::kFlexWrapKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOrder()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StylePosition()->mOrder);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAlignContent()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString str;
   auto align = StylePosition()->ComputedAlignContent();
   nsCSSValue::AppendAlignJustifyValueToString(align & NS_STYLE_ALIGN_ALL_BITS, str);
   auto fallback = align >> NS_STYLE_ALIGN_ALL_SHIFT;
   if (fallback) {
     str.Append(' ');
     nsCSSValue::AppendAlignJustifyValueToString(fallback, str);
   }
   val->SetString(str);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAlignItems()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString str;
   auto align = StylePosition()->ComputedAlignItems(StyleDisplay());
   nsCSSValue::AppendAlignJustifyValueToString(align, str);
   val->SetString(str);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAlignSelf()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   auto align = StylePosition()->
     ComputedAlignSelf(StyleDisplay(), mStyleContext->GetParent());
   nsAutoString str;
   nsCSSValue::AppendAlignJustifyValueToString(align, str);
   val->SetString(str);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetJustifyContent()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString str;
   auto justify = StylePosition()->ComputedJustifyContent(StyleDisplay());
   nsCSSValue::AppendAlignJustifyValueToString(justify & NS_STYLE_JUSTIFY_ALL_BITS, str);
   auto fallback = justify >> NS_STYLE_JUSTIFY_ALL_SHIFT;
   if (fallback) {
     MOZ_ASSERT(nsCSSProps::ValueToKeywordEnum(fallback & ~NS_STYLE_JUSTIFY_FLAG_BITS,
                                               nsCSSProps::kAlignSelfPosition)
                != eCSSKeyword_UNKNOWN, "unknown fallback value");
     str.Append(' ');
     nsCSSValue::AppendAlignJustifyValueToString(fallback, str);
   }
   val->SetString(str);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetJustifyItems()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString str;
   auto justify = StylePosition()->
     ComputedJustifyItems(StyleDisplay(), mStyleContext->GetParent());
   nsCSSValue::AppendAlignJustifyValueToString(justify, str);
   val->SetString(str);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetJustifySelf()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString str;
   auto justify = StylePosition()->
     ComputedJustifySelf(StyleDisplay(), mStyleContext->GetParent());
   nsCSSValue::AppendAlignJustifyValueToString(justify, str);
   val->SetString(str);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFloatEdge()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleBorder()->mFloatEdge,
                                    nsCSSProps::kFloatEdgeKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetForceBrokenImageIcon()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleUIReset()->mForceBrokenImageIcon);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetImageOrientation()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString string;
   nsStyleImageOrientation orientation = StyleVisibility()->mImageOrientation;
 
   if (orientation.IsFromImage()) {
     string.AppendLiteral("from-image");
   } else {
     nsStyleUtil::AppendAngleValue(orientation.AngleAsCoord(), string);
 
     if (orientation.IsFlipped()) {
       string.AppendLiteral(" flip");
     }
   }
 
   val->SetString(string);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetIMEMode()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mIMEMode,
                                    nsCSSProps::kIMEModeKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetUserFocus()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserFocus,
                                    nsCSSProps::kUserFocusKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetUserInput()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserInput,
                                    nsCSSProps::kUserInputKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetUserModify()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserModify,
                                    nsCSSProps::kUserModifyKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetUserSelect()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleUIReset()->mUserSelect,
                                    nsCSSProps::kUserSelectKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetDisplay()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mDisplay,
                                                nsCSSProps::kDisplayKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetContain()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t mask = StyleDisplay()->mContain;
 
   if (mask == 0) {
     val->SetIdent(eCSSKeyword_none);
   } else if (mask & NS_STYLE_CONTAIN_STRICT) {
     NS_ASSERTION(mask == (NS_STYLE_CONTAIN_STRICT | NS_STYLE_CONTAIN_ALL_BITS),
                  "contain: strict should imply contain: layout style paint");
@@ -4389,32 +4368,32 @@ nsComputedDOMStyle::DoGetContain()
     nsAutoString valueStr;
 
     nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_contain,
                                        mask, NS_STYLE_CONTAIN_LAYOUT,
                                        NS_STYLE_CONTAIN_PAINT, valueStr);
     val->SetString(valueStr);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPosition()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mPosition,
                                                nsCSSProps::kPositionKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetClip()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleDisplay* display = StyleDisplay();
 
   if (display->mClipFlags == NS_STYLE_CLIP_AUTO) {
     val->SetIdent(eCSSKeyword_auto);
   } else {
     // create the cssvalues for the sides, stick them in the rect object
     nsROCSSPrimitiveValue *topVal    = new nsROCSSPrimitiveValue;
@@ -4444,161 +4423,161 @@ nsComputedDOMStyle::DoGetClip()
     if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) {
       leftVal->SetIdent(eCSSKeyword_auto);
     } else {
       leftVal->SetAppUnits(display->mClip.x);
     }
     val->SetRect(domRect);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWillChange()
 {
   const nsTArray<nsString>& willChange = StyleDisplay()->mWillChange;
 
   if (willChange.IsEmpty()) {
-    nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_auto);
-    return val;
-  }
-
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
   for (size_t i = 0; i < willChange.Length(); i++) {
     const nsString& willChangeIdentifier = willChange[i];
     RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
     property->SetString(willChangeIdentifier);
     valueList->AppendCSSValue(property.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOverflow()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
   if (display->mOverflowX != display->mOverflowY) {
     // No value to return.  We can't express this combination of
     // values as a shorthand.
     return nullptr;
   }
 
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(display->mOverflowX,
                                                nsCSSProps::kOverflowKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOverflowX()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowX,
                                    nsCSSProps::kOverflowSubKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOverflowY()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY,
                                    nsCSSProps::kOverflowSubKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOverflowClipBox()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
                                    nsCSSProps::kOverflowClipBoxKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetResize()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mResize,
                                                nsCSSProps::kResizeKTable));
-  return val;
-}
-
-
-CSSValue*
+  return val.forget();
+}
+
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPageBreakAfter()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleDisplay *display = StyleDisplay();
 
   if (display->mBreakAfter) {
     val->SetIdent(eCSSKeyword_always);
   } else {
     val->SetIdent(eCSSKeyword_auto);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPageBreakBefore()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleDisplay *display = StyleDisplay();
 
   if (display->mBreakBefore) {
     val->SetIdent(eCSSKeyword_always);
   } else {
     val->SetIdent(eCSSKeyword_auto);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPageBreakInside()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mBreakInside,
                                                nsCSSProps::kPageBreakInsideKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTouchAction()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   int32_t intValue = StyleDisplay()->mTouchAction;
 
   // None and Auto and Manipulation values aren't allowed
   // to be in conjunction with other values.
   // But there are all checks in CSSParserImpl::ParseTouchAction
   nsAutoString valueStr;
   nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action, intValue,
     NS_STYLE_TOUCH_ACTION_NONE, NS_STYLE_TOUCH_ACTION_MANIPULATION,
     valueStr);
   val->SetString(valueStr);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetHeight()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   bool calcHeight = false;
 
   if (mInnerFrame) {
     calcHeight = true;
 
     const nsStyleDisplay* displayData = StyleDisplay();
     if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
@@ -4626,23 +4605,23 @@ nsComputedDOMStyle::DoGetHeight()
       StyleCoordToNSCoord(positionData->mMaxHeight,
                           &nsComputedDOMStyle::GetCBContentHeight,
                           nscoord_MAX, true);
 
     SetValueToCoord(val, positionData->mHeight, true, nullptr,
                     nsCSSProps::kWidthKTable, minHeight, maxHeight);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWidth()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   bool calcWidth = false;
 
   if (mInnerFrame) {
     calcWidth = true;
 
     const nsStyleDisplay *displayData = StyleDisplay();
     if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
@@ -4670,63 +4649,63 @@ nsComputedDOMStyle::DoGetWidth()
       StyleCoordToNSCoord(positionData->mMaxWidth,
                           &nsComputedDOMStyle::GetCBContentWidth,
                           nscoord_MAX, true);
 
     SetValueToCoord(val, positionData->mWidth, true, nullptr,
                     nsCSSProps::kWidthKTable, minWidth, maxWidth);
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMaxHeight()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StylePosition()->mMaxHeight, true,
                   &nsComputedDOMStyle::GetCBContentHeight,
                   nsCSSProps::kWidthKTable);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMaxWidth()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StylePosition()->mMaxWidth, true,
                   &nsComputedDOMStyle::GetCBContentWidth,
                   nsCSSProps::kWidthKTable);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMinHeight()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsStyleCoord minHeight = StylePosition()->mMinHeight;
 
   if (eStyleUnit_Auto == minHeight.GetUnit()) {
     // In non-flexbox contexts, "min-height: auto" means "min-height: 0"
     // XXXdholbert For flex items, we should set |minHeight| to the
     // -moz-min-content keyword, instead of 0, once we support -moz-min-content
     // as a height value.
     minHeight.SetCoordValue(0);
   }
 
   SetValueToCoord(val, minHeight, true,
                   &nsComputedDOMStyle::GetCBContentHeight,
                   nsCSSProps::kWidthKTable);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMinWidth()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   nsStyleCoord minWidth = StylePosition()->mMinWidth;
 
   if (eStyleUnit_Auto == minWidth.GetUnit()) {
     // "min-width: auto" means "0", unless we're a flex item in a horizontal
     // flex container, in which case it means "min-content"
     minWidth.SetCoordValue(0);
     if (mOuterFrame && mOuterFrame->IsFlexItem()) {
@@ -4738,79 +4717,79 @@ nsComputedDOMStyle::DoGetMinWidth()
       if (static_cast<nsFlexContainerFrame*>(flexContainer)->IsHorizontal()) {
         minWidth.SetIntValue(NS_STYLE_WIDTH_MIN_CONTENT, eStyleUnit_Enumerated);
       }
     }
   }
   SetValueToCoord(val, minWidth, true,
                   &nsComputedDOMStyle::GetCBContentWidth,
                   nsCSSProps::kWidthKTable);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMixBlendMode()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mMixBlendMode,
                                                nsCSSProps::kBlendModeKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetIsolation()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mIsolation,
                                                nsCSSProps::kIsolationKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetObjectFit()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StylePosition()->mObjectFit,
                                                nsCSSProps::kObjectFitKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetObjectPosition()
 {
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   SetValueToPosition(StylePosition()->mObjectPosition, valueList);
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetLeft()
 {
   return GetOffsetWidthFor(NS_SIDE_LEFT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetRight()
 {
   return GetOffsetWidthFor(NS_SIDE_RIGHT);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTop()
 {
   return GetOffsetWidthFor(NS_SIDE_TOP);
 }
 
 nsDOMCSSValueList*
 nsComputedDOMStyle::GetROCSSValueList(bool aCommaDelimited)
 {
   return new nsDOMCSSValueList(aCommaDelimited, true);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetOffsetWidthFor(mozilla::css::Side aSide)
 {
   const nsStyleDisplay* display = StyleDisplay();
 
   AssertFlushedPendingReflows();
 
   uint8_t position = display->mPosition;
   if (!mOuterFrame) {
@@ -4831,17 +4810,17 @@ nsComputedDOMStyle::GetOffsetWidthFor(mo
     case NS_STYLE_POSITION_FIXED:
       return GetAbsoluteOffset(aSide);
     default:
       NS_ERROR("Invalid position");
       return nullptr;
   }
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetAbsoluteOffset(mozilla::css::Side aSide)
 {
   MOZ_ASSERT(mOuterFrame, "need a frame, so we can call GetContainingBlock()");
 
   nsIFrame* container = mOuterFrame->GetContainingBlock();
   nsMargin margin = mOuterFrame->GetUsedMargin();
   nsMargin border = container->GetUsedBorder();
   nsMargin scrollbarSizes(0, 0, 0, 0);
@@ -4882,30 +4861,30 @@ nsComputedDOMStyle::GetAbsoluteOffset(mo
       offset = rect.x - margin.left - border.left - scrollbarSizes.left;
 
       break;
     default:
       NS_ERROR("Invalid side");
       break;
   }
 
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetAppUnits(offset);
-  return val;
+  return val.forget();
 }
 
 static_assert(NS_SIDE_TOP == 0 && NS_SIDE_RIGHT == 1 &&
               NS_SIDE_BOTTOM == 2 && NS_SIDE_LEFT == 3,
               "box side constants not as expected for NS_OPPOSITE_SIDE");
 #define NS_OPPOSITE_SIDE(s_) mozilla::css::Side(((s_) + 2) & 3)
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetRelativeOffset(mozilla::css::Side aSide)
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStylePosition* positionData = StylePosition();
   int32_t sign = 1;
   nsStyleCoord coord = positionData->mOffset.Get(aSide);
 
   NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
                coord.GetUnit() == eStyleUnit_Percent ||
                coord.GetUnit() == eStyleUnit_Auto ||
@@ -4919,72 +4898,72 @@ nsComputedDOMStyle::GetRelativeOffset(mo
   PercentageBaseGetter baseGetter;
   if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
     baseGetter = &nsComputedDOMStyle::GetCBContentWidth;
   } else {
     baseGetter = &nsComputedDOMStyle::GetCBContentHeight;
   }
 
   val->SetAppUnits(sign * StyleCoordToNSCoord(coord, baseGetter, 0, false));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetStickyOffset(mozilla::css::Side aSide)
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStylePosition* positionData = StylePosition();
   nsStyleCoord coord = positionData->mOffset.Get(aSide);
 
   NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord ||
                coord.GetUnit() == eStyleUnit_Percent ||
                coord.GetUnit() == eStyleUnit_Auto ||
                coord.IsCalcUnit(),
                "Unexpected unit");
 
   if (coord.GetUnit() == eStyleUnit_Auto) {
     val->SetIdent(eCSSKeyword_auto);
-    return val;
+    return val.forget();
   }
   PercentageBaseGetter baseGetter;
   if (aSide == NS_SIDE_LEFT || aSide == NS_SIDE_RIGHT) {
     baseGetter = &nsComputedDOMStyle::GetScrollFrameContentWidth;
   } else {
     baseGetter = &nsComputedDOMStyle::GetScrollFrameContentHeight;
   }
 
   val->SetAppUnits(StyleCoordToNSCoord(coord, baseGetter, 0, false));
-  return val;
-}
-
-
-CSSValue*
+  return val.forget();
+}
+
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetStaticOffset(mozilla::css::Side aSide)
 
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StylePosition()->mOffset.Get(aSide), false);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetPaddingWidthFor(mozilla::css::Side aSide)
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   if (!mInnerFrame) {
     SetValueToCoord(val, StylePadding()->mPadding.Get(aSide), true);
   } else {
     AssertFlushedPendingReflows();
 
     val->SetAppUnits(mInnerFrame->GetUsedPadding().Side(aSide));
   }
 
-  return val;
+  return val.forget();
 }
 
 bool
 nsComputedDOMStyle::GetLineHeightCoord(nscoord& aCoord)
 {
   AssertFlushedPendingReflows();
 
   nscoord blockHeight = NS_AUTOHEIGHT;
@@ -5015,106 +4994,106 @@ nsComputedDOMStyle::GetLineHeightCoord(n
   if (font->mFont.size != font->mSize) {
     fCoord = fCoord * (float(font->mSize) / float(font->mFont.size));
   }
   aCoord = NSToCoordRound(fCoord);
 
   return true;
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetBorderColorsFor(mozilla::css::Side aSide)
 {
   const nsStyleBorder *border = StyleBorder();
 
   if (border->mBorderColors) {
     nsBorderColors* borderColors = border->mBorderColors[aSide];
     if (borderColors) {
-      nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+      RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
       do {
         RefPtr<nsROCSSPrimitiveValue> primitive = new nsROCSSPrimitiveValue;
 
         SetToRGBAColor(primitive, borderColors->mColor);
 
         valueList->AppendCSSValue(primitive.forget());
         borderColors = borderColors->mNext;
       } while (borderColors);
 
-      return valueList;
+      return valueList.forget();
     }
   }
 
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(eCSSKeyword_none);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetBorderWidthFor(mozilla::css::Side aSide)
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   nscoord width;
   if (mInnerFrame) {
     AssertFlushedPendingReflows();
     width = mInnerFrame->GetUsedBorder().Side(aSide);
   } else {
     width = StyleBorder()->GetComputedBorderWidth(aSide);
   }
   val->SetAppUnits(width);
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetBorderColorFor(mozilla::css::Side aSide)
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   nscolor color;
   bool foreground;
   StyleBorder()->GetBorderColor(aSide, color, foreground);
   if (foreground) {
     color = StyleColor()->mColor;
   }
 
   SetToRGBAColor(val, color);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetMarginWidthFor(mozilla::css::Side aSide)
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   if (!mInnerFrame) {
     SetValueToCoord(val, StyleMargin()->mMargin.Get(aSide), false);
   } else {
     AssertFlushedPendingReflows();
 
     // For tables, GetUsedMargin always returns an empty margin, so we
     // should read the margin from the outer table frame instead.
     val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide));
     NS_ASSERTION(mOuterFrame == mInnerFrame ||
                  mInnerFrame->GetUsedMargin() == nsMargin(0, 0, 0, 0),
                  "Inner tables must have zero margins");
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetBorderStyleFor(mozilla::css::Side aSide)
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleBorder()->GetBorderStyle(aSide),
                                    nsCSSProps::kBorderStyleKTable));
-  return val;
+  return val.forget();
 }
 
 void
 nsComputedDOMStyle::SetValueToCoord(nsROCSSPrimitiveValue* aValue,
                                     const nsStyleCoord& aCoord,
                                     bool aClampNegativeCalc,
                                     PercentageBaseGetter aPercentageBaseGetter,
                                     const KTableEntry aTable[],
@@ -5385,20 +5364,20 @@ nsComputedDOMStyle::GetFrameBoundsHeight
   }
 
   AssertFlushedPendingReflows();
 
   aHeight = nsStyleTransformMatrix::TransformReferenceBox(mInnerFrame).Height();
   return true;
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetSVGPaintFor(bool aFill)
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleSVG* svg = StyleSVG();
   const nsStyleSVGPaint* paint = nullptr;
 
   if (aFill)
     paint = &svg->mFill;
   else
     paint = &svg->mStroke;
@@ -5413,322 +5392,315 @@ nsComputedDOMStyle::GetSVGPaintFor(bool 
     }
     case eStyleSVGPaintType_Color:
     {
       SetToRGBAColor(val, paint->mPaint.mColor);
       break;
     }
     case eStyleSVGPaintType_Server:
     {
-      nsDOMCSSValueList *valueList = GetROCSSValueList(false);
+      RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
       RefPtr<nsROCSSPrimitiveValue> fallback = new nsROCSSPrimitiveValue;
 
-      // XXXdholbert Really we should store |val| in a RefPtr right away, and
-      // our return-type should be already_AddRefed. See bug 1234676.  For now,
-      // we only put it in a RefPtr (for the benefit of AppendCSSValue) after
-      // we know we're not returning it directly.
-      RefPtr<nsROCSSPrimitiveValue> refcountedVal = val;
-      val = nullptr; // (to avoid accidental reuse/misuse)
-
-      refcountedVal->SetURI(paint->mPaint.mPaintServer);
+      val->SetURI(paint->mPaint.mPaintServer);
       SetToRGBAColor(fallback, paint->mFallbackColor);
 
-      valueList->AppendCSSValue(refcountedVal.forget());
+      valueList->AppendCSSValue(val.forget());
       valueList->AppendCSSValue(fallback.forget());
-      return valueList;
+      return valueList.forget();
     }
     case eStyleSVGPaintType_ContextFill:
     {
       val->SetIdent(eCSSKeyword_context_fill);
       break;
     }
     case eStyleSVGPaintType_ContextStroke:
     {
       val->SetIdent(eCSSKeyword_context_stroke);
       break;
     }
   }
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFill()
 {
   return GetSVGPaintFor(true);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStroke()
 {
   return GetSVGPaintFor(false);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarkerEnd()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleSVG* svg = StyleSVG();
 
   if (svg->mMarkerEnd)
     val->SetURI(svg->mMarkerEnd);
   else
     val->SetIdent(eCSSKeyword_none);
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarkerMid()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleSVG* svg = StyleSVG();
 
   if (svg->mMarkerMid)
     val->SetURI(svg->mMarkerMid);
   else
     val->SetIdent(eCSSKeyword_none);
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMarkerStart()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleSVG* svg = StyleSVG();
 
   if (svg->mMarkerStart)
     val->SetURI(svg->mMarkerStart);
   else
     val->SetIdent(eCSSKeyword_none);
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStrokeDasharray()
 {
   const nsStyleSVG* svg = StyleSVG();
 
   if (!svg->mStrokeDasharrayLength || !svg->mStrokeDasharray) {
-    nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
-    return val;
-  }
-
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   for (uint32_t i = 0; i < svg->mStrokeDasharrayLength; i++) {
     RefPtr<nsROCSSPrimitiveValue> dash = new nsROCSSPrimitiveValue;
     SetValueToCoord(dash, svg->mStrokeDasharray[i], true);
     valueList->AppendCSSValue(dash.forget());
   }
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStrokeDashoffset()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StyleSVG()->mStrokeDashoffset, false);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStrokeWidth()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StyleSVG()->mStrokeWidth, true);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetVectorEffect()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mVectorEffect,
                                                nsCSSProps::kVectorEffectKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFillOpacity()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleSVG()->mFillOpacity);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFloodOpacity()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleSVGReset()->mFloodOpacity);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStopOpacity()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleSVGReset()->mStopOpacity);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStrokeMiterlimit()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleSVG()->mStrokeMiterlimit);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStrokeOpacity()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleSVG()->mStrokeOpacity);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetClipRule()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(
                   StyleSVG()->mClipRule, nsCSSProps::kFillRuleKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFillRule()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(
                   StyleSVG()->mFillRule, nsCSSProps::kFillRuleKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStrokeLinecap()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinecap,
                                    nsCSSProps::kStrokeLinecapKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStrokeLinejoin()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mStrokeLinejoin,
                                    nsCSSProps::kStrokeLinejoinKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextAnchor()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextAnchor,
                                    nsCSSProps::kTextAnchorKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColorInterpolation()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolation,
                                    nsCSSProps::kColorInterpolationKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColorInterpolationFilters()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mColorInterpolationFilters,
                                    nsCSSProps::kColorInterpolationKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetDominantBaseline()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mDominantBaseline,
                                    nsCSSProps::kDominantBaselineKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetImageRendering()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mImageRendering,
                                    nsCSSProps::kImageRenderingKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetShapeRendering()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mShapeRendering,
                                    nsCSSProps::kShapeRenderingKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextRendering()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVG()->mTextRendering,
                                    nsCSSProps::kTextRenderingKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFloodColor()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleSVGReset()->mFloodColor);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetLightingColor()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleSVGReset()->mLightingColor);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetStopColor()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleSVGReset()->mStopColor);
-  return val;
+  return val.forget();
 }
 
 inline void AppendBasicShapeTypeToString(nsStyleBasicShape::Type aType,
                                          nsAutoString& aString)
 {
   nsCSSKeyword functionName;
   switch (aType) {
     case nsStyleBasicShape::Type::ePolygon:
@@ -5796,21 +5768,21 @@ nsComputedDOMStyle::BasicShapeRadiiToStr
   aCssText.Append(horizontalString);
   if (horizontalString == verticalString) {
     return;
   }
   aCssText.AppendLiteral(" / ");
   aCssText.Append(verticalString);
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
   const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox)
 {
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   if (aStyleBasicShape) {
     nsStyleBasicShape::Type type = aStyleBasicShape->GetShapeType();
     // Shape function name and opening parenthesis.
     nsAutoString shapeFunctionString;
     AppendBasicShapeTypeToString(type, shapeFunctionString);
     shapeFunctionString.Append('(');
     switch (type) {
       case nsStyleBasicShape::Type::ePolygon: {
@@ -5874,51 +5846,51 @@ nsComputedDOMStyle::CreatePrimitiveValue
     }
     shapeFunctionString.Append(')');
     RefPtr<nsROCSSPrimitiveValue> functionValue = new nsROCSSPrimitiveValue;
     functionValue->SetString(shapeFunctionString);
     valueList->AppendCSSValue(functionValue.forget());
   }
 
   if (aSizingBox == NS_STYLE_CLIP_SHAPE_SIZING_NOBOX) {
-    return valueList;
+    return valueList.forget();
   }
 
   nsAutoString boxString;
   AppendASCIItoUTF16(
     nsCSSProps::ValueToKeyword(aSizingBox,
                                nsCSSProps::kClipShapeSizingKTable),
                                boxString);
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetString(boxString);
   valueList->AppendCSSValue(val.forget());
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetClipPath()
 {
   const nsStyleSVGReset* svg = StyleSVGReset();
   switch (svg->mClipPath.GetType()) {
     case NS_STYLE_CLIP_PATH_SHAPE:
       return CreatePrimitiveValueForClipPath(svg->mClipPath.GetBasicShape(),
                                              svg->mClipPath.GetSizingBox());
     case NS_STYLE_CLIP_PATH_BOX:
       return CreatePrimitiveValueForClipPath(nullptr,
                                              svg->mClipPath.GetSizingBox());
     case NS_STYLE_CLIP_PATH_URL: {
-      nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+      RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
       val->SetURI(svg->mClipPath.GetURL());
-      return val;
+      return val.forget();
     }
     case NS_STYLE_CLIP_PATH_NONE: {
-      nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+      RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
       val->SetIdent(eCSSKeyword_none);
-      return val;
+      return val.forget();
     }
     default:
       NS_NOTREACHED("unexpected type");
   }
   return nullptr;
 }
 
 void
@@ -5967,118 +5939,118 @@ nsComputedDOMStyle::CreatePrimitiveValue
 
   // Filter function closing parenthesis.
   filterFunctionString.Append(')');
 
   value->SetString(filterFunctionString);
   return value.forget();
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFilter()
 {
   const nsTArray<nsStyleFilter>& filters = StyleSVGReset()->mFilters;
 
   if (filters.IsEmpty()) {
-    nsROCSSPrimitiveValue* value = new nsROCSSPrimitiveValue;
+    RefPtr<nsROCSSPrimitiveValue> value = new nsROCSSPrimitiveValue;
     value->SetIdent(eCSSKeyword_none);
-    return value;
-  }
-
-  nsDOMCSSValueList* valueList = GetROCSSValueList(false);
+    return value.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   for(uint32_t i = 0; i < filters.Length(); i++) {
     RefPtr<CSSValue> value = CreatePrimitiveValueForStyleFilter(filters[i]);
     valueList->AppendCSSValue(value.forget());
   }
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMask()
 {
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleSVGReset* svg = StyleSVGReset();
 
   if (svg->mMask)
     val->SetURI(svg->mMask);
   else
     val->SetIdent(eCSSKeyword_none);
 
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetMaskType()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleSVGReset()->mMaskType,
                                    nsCSSProps::kMaskTypeKTable));
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetPaintOrder()
 {
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString string;
   uint8_t paintOrder = StyleSVG()->mPaintOrder;
   nsStyleUtil::AppendPaintOrderValue(paintOrder, string);
   val->SetString(string);
-  return val;
-}
-
-CSSValue*
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTransitionDelay()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mTransitionDelayCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleTransition *transition = &display->mTransitions[i];
     RefPtr<nsROCSSPrimitiveValue> delay = new nsROCSSPrimitiveValue;
     delay->SetTime((float)transition->GetDelay() / (float)PR_MSEC_PER_SEC);
     valueList->AppendCSSValue(delay.forget());
   } while (++i < display->mTransitionDelayCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTransitionDuration()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mTransitionDurationCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleTransition *transition = &display->mTransitions[i];
     RefPtr<nsROCSSPrimitiveValue> duration = new nsROCSSPrimitiveValue;
 
     duration->SetTime((float)transition->GetDuration() / (float)PR_MSEC_PER_SEC);
     valueList->AppendCSSValue(duration.forget());
   } while (++i < display->mTransitionDurationCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTransitionProperty()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mTransitionPropertyCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleTransition *transition = &display->mTransitions[i];
     RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
     nsCSSProperty cssprop = transition->GetProperty();
@@ -6095,17 +6067,17 @@ nsComputedDOMStyle::DoGetTransitionPrope
       property->SetString(escaped); // really want SetIdent
     }
     else
       property->SetString(nsCSSProps::GetStringValue(cssprop));
 
     valueList->AppendCSSValue(property.forget());
   } while (++i < display->mTransitionPropertyCount);
 
-  return valueList;
+  return valueList.forget();
 }
 
 void
 nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList,
                                          const nsTimingFunction& aTimingFunction)
 {
   RefPtr<nsROCSSPrimitiveValue> timingFunction = new nsROCSSPrimitiveValue;
 
@@ -6129,40 +6101,40 @@ nsComputedDOMStyle::AppendTimingFunction
       nsStyleUtil::AppendCubicBezierKeywordTimingFunction(aTimingFunction.mType,
                                                           tmp);
       break;
   }
   timingFunction->SetString(tmp);
   aValueList->AppendCSSValue(timingFunction.forget());
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTransitionTimingFunction()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mTransitionTimingFunctionCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     AppendTimingFunction(valueList,
                          display->mTransitions[i].GetTimingFunction());
   } while (++i < display->mTransitionTimingFunctionCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAnimationName()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mAnimationNameCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleAnimation *animation = &display->mAnimations[i];
     RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
 
@@ -6172,132 +6144,132 @@ nsComputedDOMStyle::DoGetAnimationName()
     } else {
       nsAutoString escaped;
       nsStyleUtil::AppendEscapedCSSIdent(animation->GetName(), escaped);
       property->SetString(escaped); // really want SetIdent
     }
     valueList->AppendCSSValue(property.forget());
   } while (++i < display->mAnimationNameCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAnimationDelay()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mAnimationDelayCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleAnimation *animation = &display->mAnimations[i];
     RefPtr<nsROCSSPrimitiveValue> delay = new nsROCSSPrimitiveValue;
     delay->SetTime((float)animation->GetDelay() / (float)PR_MSEC_PER_SEC);
     valueList->AppendCSSValue(delay.forget());
   } while (++i < display->mAnimationDelayCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAnimationDuration()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mAnimationDurationCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleAnimation *animation = &display->mAnimations[i];
     RefPtr<nsROCSSPrimitiveValue> duration = new nsROCSSPrimitiveValue;
 
     duration->SetTime((float)animation->GetDuration() / (float)PR_MSEC_PER_SEC);
     valueList->AppendCSSValue(duration.forget());
   } while (++i < display->mAnimationDurationCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAnimationTimingFunction()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mAnimationTimingFunctionCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     AppendTimingFunction(valueList,
                          display->mAnimations[i].GetTimingFunction());
   } while (++i < display->mAnimationTimingFunctionCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAnimationDirection()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mAnimationDirectionCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleAnimation *animation = &display->mAnimations[i];
     RefPtr<nsROCSSPrimitiveValue> direction = new nsROCSSPrimitiveValue;
     direction->SetIdent(
       nsCSSProps::ValueToKeywordEnum(
         static_cast<int32_t>(animation->GetDirection()),
         nsCSSProps::kAnimationDirectionKTable));
 
     valueList->AppendCSSValue(direction.forget());
   } while (++i < display->mAnimationDirectionCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAnimationFillMode()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mAnimationFillModeCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleAnimation *animation = &display->mAnimations[i];
     RefPtr<nsROCSSPrimitiveValue> fillMode = new nsROCSSPrimitiveValue;
     fillMode->SetIdent(
       nsCSSProps::ValueToKeywordEnum(
         static_cast<int32_t>(animation->GetFillMode()),
         nsCSSProps::kAnimationFillModeKTable));
 
     valueList->AppendCSSValue(fillMode.forget());
   } while (++i < display->mAnimationFillModeCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAnimationIterationCount()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mAnimationIterationCountCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleAnimation *animation = &display->mAnimations[i];
     RefPtr<nsROCSSPrimitiveValue> iterationCount = new nsROCSSPrimitiveValue;
 
@@ -6313,65 +6285,65 @@ nsComputedDOMStyle::DoGetAnimationIterat
     if (f == inf) {
       iterationCount->SetIdent(eCSSKeyword_infinite);
     } else {
       iterationCount->SetNumber(f);
     }
     valueList->AppendCSSValue(iterationCount.forget());
   } while (++i < display->mAnimationIterationCountCount);
 
-  return valueList;
-}
-
-CSSValue*
+  return valueList.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetAnimationPlayState()
 {
   const nsStyleDisplay* display = StyleDisplay();
 
-  nsDOMCSSValueList *valueList = GetROCSSValueList(true);
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   MOZ_ASSERT(display->mAnimationPlayStateCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleAnimation *animation = &display->mAnimations[i];
     RefPtr<nsROCSSPrimitiveValue> playState = new nsROCSSPrimitiveValue;
     playState->SetIdent(
       nsCSSProps::ValueToKeywordEnum(animation->GetPlayState(),
                                      nsCSSProps::kAnimationPlayStateKTable));
     valueList->AppendCSSValue(playState.forget());
   } while (++i < display->mAnimationPlayStateCount);
 
-  return valueList;
+  return valueList.forget();
 }
 
 static void
 MarkComputedStyleMapDirty(const char* aPref, void* aData)
 {
   static_cast<nsComputedStyleMap*>(aData)->MarkDirty();
 }
 
-CSSValue*
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetCustomProperty(const nsAString& aPropertyName)
 {
   MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
 
   const nsStyleVariables* variables = StyleVariables();
 
   nsString variableValue;
   const nsAString& name = Substring(aPropertyName,
                                     CSS_CUSTOM_NAME_PREFIX_LENGTH);
   if (!variables->mVariables.Get(name, variableValue)) {
     return nullptr;
   }
 
-  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetString(variableValue);
 
-  return val;
+  return val.forget();
 }
 
 void
 nsComputedDOMStyle::ParentChainChanged(nsIContent* aContent)
 {
   NS_ASSERTION(mContent == aContent, "didn't we register mContent?");
   NS_ASSERTION(mResolvedStyleContext,
                "should have only registered an observer when "
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -42,27 +42,30 @@ struct nsStyleFilter;
 class nsStyleGradient;
 struct nsStyleImage;
 class nsStyleSides;
 struct nsTimingFunction;
 
 class nsComputedDOMStyle final : public nsDOMCSSDeclaration
                                , public nsStubMutationObserver
 {
-public:
+private:
+  // Convenience typedefs:
   typedef nsCSSProps::KTableEntry KTableEntry;
+  typedef mozilla::dom::CSSValue CSSValue;
 
+public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsComputedDOMStyle,
                                                                    nsICSSDeclaration)
 
   NS_DECL_NSICSSDECLARATION
 
   NS_DECL_NSIDOMCSSSTYLEDECLARATION_HELPER
-  virtual already_AddRefed<mozilla::dom::CSSValue>
+  virtual already_AddRefed<CSSValue>
   GetPropertyCSSValue(const nsAString& aProp, mozilla::ErrorResult& aRv)
     override;
   using nsICSSDeclaration::GetPropertyCSSValue;
   virtual void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aPropName) override;
 
   enum StyleType {
     eDefaultOnly, // Only includes UA and user sheets
     eAll // Includes all stylesheets
@@ -101,17 +104,18 @@ public:
   // nsDOMCSSDeclaration abstract methods which should never be called
   // on a nsComputedDOMStyle object, but must be defined to avoid
   // compile errors.
   virtual mozilla::css::Declaration* GetCSSDeclaration(Operation) override;
   virtual nsresult SetCSSDeclaration(mozilla::css::Declaration*) override;
   virtual nsIDocument* DocToUpdate() override;
   virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) override;
 
-  static nsROCSSPrimitiveValue* MatrixToCSSValue(const mozilla::gfx::Matrix4x4& aMatrix);
+  static already_AddRefed<nsROCSSPrimitiveValue>
+    MatrixToCSSValue(const mozilla::gfx::Matrix4x4& aMatrix);
 
   static void RegisterPrefChangeCallbacks();
   static void UnregisterPrefChangeCallbacks();
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
 
 private:
@@ -120,435 +124,433 @@ private:
   void AssertFlushedPendingReflows() {
     NS_ASSERTION(mFlushedPendingReflows,
                  "property getter should have been marked layout-dependent");
   }
 
   nsMargin GetAdjustedValuesForBoxSizing();
 
   // Helper method for DoGetTextAlign[Last].
-  mozilla::dom::CSSValue* CreateTextAlignValue(uint8_t aAlign,
-                                               bool aAlignTrue,
-                                               const KTableEntry aTable[]);
+  already_AddRefed<CSSValue> CreateTextAlignValue(uint8_t aAlign,
+                                                  bool aAlignTrue,
+                                                  const KTableEntry aTable[]);
   // This indicates error by leaving mStyleContext null.
   void UpdateCurrentStyleSources(bool aNeedsLayoutFlush);
   void ClearCurrentStyleSources();
 
   // Helper functions called by UpdateCurrentStyleSources.
   void ClearStyleContext();
   void SetResolvedStyleContext(RefPtr<nsStyleContext>&& aContext);
   void SetFrameStyleContext(nsStyleContext* aContext);
 
 #define STYLE_STRUCT(name_, checkdata_cb_)                              \
   const nsStyle##name_ * Style##name_() {                               \
     return mStyleContext->Style##name_();                               \
   }
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 
-  // All of the property getters below return a pointer to a refcounted object
-  // that has just been created, but the refcount is still 0. Caller must take
-  // ownership.
+  already_AddRefed<CSSValue> GetEllipseRadii(const nsStyleCorners& aRadius,
+                                             uint8_t aFullCorner,
+                                             bool aIsBorder); // else outline
 
-  mozilla::dom::CSSValue* GetEllipseRadii(const nsStyleCorners& aRadius,
-                                          uint8_t aFullCorner,
-                                          bool aIsBorder); // else outline
+  already_AddRefed<CSSValue> GetOffsetWidthFor(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetOffsetWidthFor(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetAbsoluteOffset(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetAbsoluteOffset(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetRelativeOffset(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetRelativeOffset(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetStickyOffset(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetStickyOffset(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetStaticOffset(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetStaticOffset(mozilla::css::Side aSide);
-
-  mozilla::dom::CSSValue* GetPaddingWidthFor(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetPaddingWidthFor(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetBorderColorsFor(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetBorderColorsFor(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetBorderStyleFor(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetBorderStyleFor(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetBorderWidthFor(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetBorderWidthFor(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetBorderColorFor(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetBorderColorFor(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetMarginWidthFor(mozilla::css::Side aSide);
+  already_AddRefed<CSSValue> GetMarginWidthFor(mozilla::css::Side aSide);
 
-  mozilla::dom::CSSValue* GetSVGPaintFor(bool aFill);
+  already_AddRefed<CSSValue> GetSVGPaintFor(bool aFill);
 
   // Appends all aLineNames (must be non-empty) space-separated to aResult.
   void AppendGridLineNames(nsString& aResult,
                            const nsTArray<nsString>& aLineNames);
   // Appends aLineNames (if non-empty) as a CSSValue* to aValueList.
   void AppendGridLineNames(nsDOMCSSValueList* aValueList,
                            const nsTArray<nsString>& aLineNames);
   // Appends aLineNames1/2 (if non-empty) as a CSSValue* to aValueList.
   void AppendGridLineNames(nsDOMCSSValueList* aValueList,
                            const nsTArray<nsString>& aLineNames1,
                            const nsTArray<nsString>& aLineNames2);
-  mozilla::dom::CSSValue* GetGridTrackSize(const nsStyleCoord& aMinSize,
-                                           const nsStyleCoord& aMaxSize);
-  mozilla::dom::CSSValue* GetGridTemplateColumnsRows(const nsStyleGridTemplate& aTrackList,
-                                                     const nsTArray<nscoord>* aTrackSizes);
-  mozilla::dom::CSSValue* GetGridLine(const nsStyleGridLine& aGridLine);
+  already_AddRefed<CSSValue> GetGridTrackSize(const nsStyleCoord& aMinSize,
+                                              const nsStyleCoord& aMaxSize);
+  already_AddRefed<CSSValue> GetGridTemplateColumnsRows(
+    const nsStyleGridTemplate& aTrackList,
+    const nsTArray<nscoord>* aTrackSizes);
+  already_AddRefed<CSSValue> GetGridLine(const nsStyleGridLine& aGridLine);
 
   bool GetLineHeightCoord(nscoord& aCoord);
 
-  mozilla::dom::CSSValue* GetCSSShadowArray(nsCSSShadowArray* aArray,
-                                            const nscolor& aDefaultColor,
-                                            bool aIsBoxShadow);
+  already_AddRefed<CSSValue> GetCSSShadowArray(nsCSSShadowArray* aArray,
+                                               const nscolor& aDefaultColor,
+                                               bool aIsBoxShadow);
 
-  mozilla::dom::CSSValue* GetBackgroundList(uint8_t nsStyleBackground::Layer::* aMember,
-                                            uint32_t nsStyleBackground::* aCount,
-                                            const KTableEntry aTable[]);
+  already_AddRefed<CSSValue> GetBackgroundList(
+    uint8_t nsStyleBackground::Layer::* aMember,
+    uint32_t nsStyleBackground::* aCount,
+    const KTableEntry aTable[]);
 
   void GetCSSGradientString(const nsStyleGradient* aGradient,
                             nsAString& aString);
   void GetImageRectString(nsIURI* aURI,
                           const nsStyleSides& aCropRect,
                           nsString& aString);
-  mozilla::dom::CSSValue* GetScrollSnapPoints(const nsStyleCoord& aCoord);
+  already_AddRefed<CSSValue> GetScrollSnapPoints(const nsStyleCoord& aCoord);
   void AppendTimingFunction(nsDOMCSSValueList *aValueList,
                             const nsTimingFunction& aTimingFunction);
 
   /* Properties queryable as CSSValues.
    * To avoid a name conflict with nsIDOM*CSS2Properties, these are all
    * DoGetXXX instead of GetXXX.
    */
 
-  mozilla::dom::CSSValue* DoGetAppearance();
+  already_AddRefed<CSSValue> DoGetAppearance();
 
   /* Box properties */
-  mozilla::dom::CSSValue* DoGetBoxAlign();
-  mozilla::dom::CSSValue* DoGetBoxDecorationBreak();
-  mozilla::dom::CSSValue* DoGetBoxDirection();
-  mozilla::dom::CSSValue* DoGetBoxFlex();
-  mozilla::dom::CSSValue* DoGetBoxOrdinalGroup();
-  mozilla::dom::CSSValue* DoGetBoxOrient();
-  mozilla::dom::CSSValue* DoGetBoxPack();
-  mozilla::dom::CSSValue* DoGetBoxSizing();
+  already_AddRefed<CSSValue> DoGetBoxAlign();
+  already_AddRefed<CSSValue> DoGetBoxDecorationBreak();
+  already_AddRefed<CSSValue> DoGetBoxDirection();
+  already_AddRefed<CSSValue> DoGetBoxFlex();
+  already_AddRefed<CSSValue> DoGetBoxOrdinalGroup();
+  already_AddRefed<CSSValue> DoGetBoxOrient();
+  already_AddRefed<CSSValue> DoGetBoxPack();
+  already_AddRefed<CSSValue> DoGetBoxSizing();
 
-  mozilla::dom::CSSValue* DoGetWidth();
-  mozilla::dom::CSSValue* DoGetHeight();
-  mozilla::dom::CSSValue* DoGetMaxHeight();
-  mozilla::dom::CSSValue* DoGetMaxWidth();
-  mozilla::dom::CSSValue* DoGetMinHeight();
-  mozilla::dom::CSSValue* DoGetMinWidth();
-  mozilla::dom::CSSValue* DoGetMixBlendMode();
-  mozilla::dom::CSSValue* DoGetIsolation();
-  mozilla::dom::CSSValue* DoGetObjectFit();
-  mozilla::dom::CSSValue* DoGetObjectPosition();
-  mozilla::dom::CSSValue* DoGetLeft();
-  mozilla::dom::CSSValue* DoGetTop();
-  mozilla::dom::CSSValue* DoGetRight();
-  mozilla::dom::CSSValue* DoGetBottom();
-  mozilla::dom::CSSValue* DoGetStackSizing();
+  already_AddRefed<CSSValue> DoGetWidth();
+  already_AddRefed<CSSValue> DoGetHeight();
+  already_AddRefed<CSSValue> DoGetMaxHeight();
+  already_AddRefed<CSSValue> DoGetMaxWidth();
+  already_AddRefed<CSSValue> DoGetMinHeight();
+  already_AddRefed<CSSValue> DoGetMinWidth();
+  already_AddRefed<CSSValue> DoGetMixBlendMode();
+  already_AddRefed<CSSValue> DoGetIsolation();
+  already_AddRefed<CSSValue> DoGetObjectFit();
+  already_AddRefed<CSSValue> DoGetObjectPosition();
+  already_AddRefed<CSSValue> DoGetLeft();
+  already_AddRefed<CSSValue> DoGetTop();
+  already_AddRefed<CSSValue> DoGetRight();
+  already_AddRefed<CSSValue> DoGetBottom();
+  already_AddRefed<CSSValue> DoGetStackSizing();
 
   /* Font properties */
-  mozilla::dom::CSSValue* DoGetColor();
-  mozilla::dom::CSSValue* DoGetFontFamily();
-  mozilla::dom::CSSValue* DoGetFontFeatureSettings();
-  mozilla::dom::CSSValue* DoGetFontKerning();
-  mozilla::dom::CSSValue* DoGetFontLanguageOverride();
-  mozilla::dom::CSSValue* DoGetFontSize();
-  mozilla::dom::CSSValue* DoGetFontSizeAdjust();
-  mozilla::dom::CSSValue* DoGetOsxFontSmoothing();
-  mozilla::dom::CSSValue* DoGetFontStretch();
-  mozilla::dom::CSSValue* DoGetFontStyle();
-  mozilla::dom::CSSValue* DoGetFontSynthesis();
-  mozilla::dom::CSSValue* DoGetFontVariant();
-  mozilla::dom::CSSValue* DoGetFontVariantAlternates();
-  mozilla::dom::CSSValue* DoGetFontVariantCaps();
-  mozilla::dom::CSSValue* DoGetFontVariantEastAsian();
-  mozilla::dom::CSSValue* DoGetFontVariantLigatures();
-  mozilla::dom::CSSValue* DoGetFontVariantNumeric();
-  mozilla::dom::CSSValue* DoGetFontVariantPosition();
-  mozilla::dom::CSSValue* DoGetFontWeight();
+  already_AddRefed<CSSValue> DoGetColor();
+  already_AddRefed<CSSValue> DoGetFontFamily();
+  already_AddRefed<CSSValue> DoGetFontFeatureSettings();
+  already_AddRefed<CSSValue> DoGetFontKerning();
+  already_AddRefed<CSSValue> DoGetFontLanguageOverride();
+  already_AddRefed<CSSValue> DoGetFontSize();
+  already_AddRefed<CSSValue> DoGetFontSizeAdjust();
+  already_AddRefed<CSSValue> DoGetOsxFontSmoothing();
+  already_AddRefed<CSSValue> DoGetFontStretch();
+  already_AddRefed<CSSValue> DoGetFontStyle();
+  already_AddRefed<CSSValue> DoGetFontSynthesis();
+  already_AddRefed<CSSValue> DoGetFontVariant();
+  already_AddRefed<CSSValue> DoGetFontVariantAlternates();
+  already_AddRefed<CSSValue> DoGetFontVariantCaps();
+  already_AddRefed<CSSValue> DoGetFontVariantEastAsian();
+  already_AddRefed<CSSValue> DoGetFontVariantLigatures();
+  already_AddRefed<CSSValue> DoGetFontVariantNumeric();
+  already_AddRefed<CSSValue> DoGetFontVariantPosition();
+  already_AddRefed<CSSValue> DoGetFontWeight();
 
   /* Grid properties */
-  mozilla::dom::CSSValue* DoGetGridAutoFlow();
-  mozilla::dom::CSSValue* DoGetGridAutoColumns();
-  mozilla::dom::CSSValue* DoGetGridAutoRows();
-  mozilla::dom::CSSValue* DoGetGridTemplateAreas();
-  mozilla::dom::CSSValue* DoGetGridTemplateColumns();
-  mozilla::dom::CSSValue* DoGetGridTemplateRows();
-  mozilla::dom::CSSValue* DoGetGridColumnStart();
-  mozilla::dom::CSSValue* DoGetGridColumnEnd();
-  mozilla::dom::CSSValue* DoGetGridRowStart();
-  mozilla::dom::CSSValue* DoGetGridRowEnd();
-  mozilla::dom::CSSValue* DoGetGridColumnGap();
-  mozilla::dom::CSSValue* DoGetGridRowGap();
+  already_AddRefed<CSSValue> DoGetGridAutoFlow();
+  already_AddRefed<CSSValue> DoGetGridAutoColumns();
+  already_AddRefed<CSSValue> DoGetGridAutoRows();
+  already_AddRefed<CSSValue> DoGetGridTemplateAreas();
+  already_AddRefed<CSSValue> DoGetGridTemplateColumns();
+  already_AddRefed<CSSValue> DoGetGridTemplateRows();
+  already_AddRefed<CSSValue> DoGetGridColumnStart();
+  already_AddRefed<CSSValue> DoGetGridColumnEnd();
+  already_AddRefed<CSSValue> DoGetGridRowStart();
+  already_AddRefed<CSSValue> DoGetGridRowEnd();
+  already_AddRefed<CSSValue> DoGetGridColumnGap();
+  already_AddRefed<CSSValue> DoGetGridRowGap();
 
   /* Background properties */
-  mozilla::dom::CSSValue* DoGetBackgroundAttachment();
-  mozilla::dom::CSSValue* DoGetBackgroundColor();
-  mozilla::dom::CSSValue* DoGetBackgroundImage();
-  mozilla::dom::CSSValue* DoGetBackgroundPosition();
-  mozilla::dom::CSSValue* DoGetBackgroundRepeat();
-  mozilla::dom::CSSValue* DoGetBackgroundClip();
-  mozilla::dom::CSSValue* DoGetBackgroundBlendMode();
-  mozilla::dom::CSSValue* DoGetBackgroundOrigin();
-  mozilla::dom::CSSValue* DoGetBackgroundSize();
+  already_AddRefed<CSSValue> DoGetBackgroundAttachment();
+  already_AddRefed<CSSValue> DoGetBackgroundColor();
+  already_AddRefed<CSSValue> DoGetBackgroundImage();
+  already_AddRefed<CSSValue> DoGetBackgroundPosition();
+  already_AddRefed<CSSValue> DoGetBackgroundRepeat();
+  already_AddRefed<CSSValue> DoGetBackgroundClip();
+  already_AddRefed<CSSValue> DoGetBackgroundBlendMode();
+  already_AddRefed<CSSValue> DoGetBackgroundOrigin();
+  already_AddRefed<CSSValue> DoGetBackgroundSize();
 
   /* Padding properties */
-  mozilla::dom::CSSValue* DoGetPaddingTop();
-  mozilla::dom::CSSValue* DoGetPaddingBottom();
-  mozilla::dom::CSSValue* DoGetPaddingLeft();
-  mozilla::dom::CSSValue* DoGetPaddingRight();
+  already_AddRefed<CSSValue> DoGetPaddingTop();
+  already_AddRefed<CSSValue> DoGetPaddingBottom();
+  already_AddRefed<CSSValue> DoGetPaddingLeft();
+  already_AddRefed<CSSValue> DoGetPaddingRight();
 
   /* Table Properties */
-  mozilla::dom::CSSValue* DoGetBorderCollapse();
-  mozilla::dom::CSSValue* DoGetBorderSpacing();
-  mozilla::dom::CSSValue* DoGetCaptionSide();
-  mozilla::dom::CSSValue* DoGetEmptyCells();
-  mozilla::dom::CSSValue* DoGetTableLayout();
-  mozilla::dom::CSSValue* DoGetVerticalAlign();
+  already_AddRefed<CSSValue> DoGetBorderCollapse();
+  already_AddRefed<CSSValue> DoGetBorderSpacing();
+  already_AddRefed<CSSValue> DoGetCaptionSide();
+  already_AddRefed<CSSValue> DoGetEmptyCells();
+  already_AddRefed<CSSValue> DoGetTableLayout();
+  already_AddRefed<CSSValue> DoGetVerticalAlign();
 
   /* Border Properties */
-  mozilla::dom::CSSValue* DoGetBorderTopStyle();
-  mozilla::dom::CSSValue* DoGetBorderBottomStyle();
-  mozilla::dom::CSSValue* DoGetBorderLeftStyle();
-  mozilla::dom::CSSValue* DoGetBorderRightStyle();
-  mozilla::dom::CSSValue* DoGetBorderTopWidth();
-  mozilla::dom::CSSValue* DoGetBorderBottomWidth();
-  mozilla::dom::CSSValue* DoGetBorderLeftWidth();
-  mozilla::dom::CSSValue* DoGetBorderRightWidth();
-  mozilla::dom::CSSValue* DoGetBorderTopColor();
-  mozilla::dom::CSSValue* DoGetBorderBottomColor();
-  mozilla::dom::CSSValue* DoGetBorderLeftColor();
-  mozilla::dom::CSSValue* DoGetBorderRightColor();
-  mozilla::dom::CSSValue* DoGetBorderBottomColors();
-  mozilla::dom::CSSValue* DoGetBorderLeftColors();
-  mozilla::dom::CSSValue* DoGetBorderRightColors();
-  mozilla::dom::CSSValue* DoGetBorderTopColors();
-  mozilla::dom::CSSValue* DoGetBorderBottomLeftRadius();
-  mozilla::dom::CSSValue* DoGetBorderBottomRightRadius();
-  mozilla::dom::CSSValue* DoGetBorderTopLeftRadius();
-  mozilla::dom::CSSValue* DoGetBorderTopRightRadius();
-  mozilla::dom::CSSValue* DoGetFloatEdge();
+  already_AddRefed<CSSValue> DoGetBorderTopStyle();
+  already_AddRefed<CSSValue> DoGetBorderBottomStyle();
+  already_AddRefed<CSSValue> DoGetBorderLeftStyle();
+  already_AddRefed<CSSValue> DoGetBorderRightStyle();
+  already_AddRefed<CSSValue> DoGetBorderTopWidth();
+  already_AddRefed<CSSValue> DoGetBorderBottomWidth();
+  already_AddRefed<CSSValue> DoGetBorderLeftWidth();
+  already_AddRefed<CSSValue> DoGetBorderRightWidth();
+  already_AddRefed<CSSValue> DoGetBorderTopColor();
+  already_AddRefed<CSSValue> DoGetBorderBottomColor();
+  already_AddRefed<CSSValue> DoGetBorderLeftColor();
+  already_AddRefed<CSSValue> DoGetBorderRightColor();
+  already_AddRefed<CSSValue> DoGetBorderBottomColors();
+  already_AddRefed<CSSValue> DoGetBorderLeftColors();
+  already_AddRefed<CSSValue> DoGetBorderRightColors();
+  already_AddRefed<CSSValue> DoGetBorderTopColors();
+  already_AddRefed<CSSValue> DoGetBorderBottomLeftRadius();
+  already_AddRefed<CSSValue> DoGetBorderBottomRightRadius();
+  already_AddRefed<CSSValue> DoGetBorderTopLeftRadius();
+  already_AddRefed<CSSValue> DoGetBorderTopRightRadius();
+  already_AddRefed<CSSValue> DoGetFloatEdge();
 
   /* Border Image */
-  mozilla::dom::CSSValue* DoGetBorderImageSource();
-  mozilla::dom::CSSValue* DoGetBorderImageSlice();
-  mozilla::dom::CSSValue* DoGetBorderImageWidth();
-  mozilla::dom::CSSValue* DoGetBorderImageOutset();
-  mozilla::dom::CSSValue* DoGetBorderImageRepeat();
+  already_AddRefed<CSSValue> DoGetBorderImageSource();
+  already_AddRefed<CSSValue> DoGetBorderImageSlice();
+  already_AddRefed<CSSValue> DoGetBorderImageWidth();
+  already_AddRefed<CSSValue> DoGetBorderImageOutset();
+  already_AddRefed<CSSValue> DoGetBorderImageRepeat();
 
   /* Box Shadow */
-  mozilla::dom::CSSValue* DoGetBoxShadow();
+  already_AddRefed<CSSValue> DoGetBoxShadow();
 
   /* Window Shadow */
-  mozilla::dom::CSSValue* DoGetWindowShadow();
+  already_AddRefed<CSSValue> DoGetWindowShadow();
 
   /* Margin Properties */
-  mozilla::dom::CSSValue* DoGetMarginTopWidth();
-  mozilla::dom::CSSValue* DoGetMarginBottomWidth();
-  mozilla::dom::CSSValue* DoGetMarginLeftWidth();
-  mozilla::dom::CSSValue* DoGetMarginRightWidth();
+  already_AddRefed<CSSValue> DoGetMarginTopWidth();
+  already_AddRefed<CSSValue> DoGetMarginBottomWidth();
+  already_AddRefed<CSSValue> DoGetMarginLeftWidth();
+  already_AddRefed<CSSValue> DoGetMarginRightWidth();
 
   /* Outline Properties */
-  mozilla::dom::CSSValue* DoGetOutlineWidth();
-  mozilla::dom::CSSValue* DoGetOutlineStyle();
-  mozilla::dom::CSSValue* DoGetOutlineColor();
-  mozilla::dom::CSSValue* DoGetOutlineOffset();
-  mozilla::dom::CSSValue* DoGetOutlineRadiusBottomLeft();
-  mozilla::dom::CSSValue* DoGetOutlineRadiusBottomRight();
-  mozilla::dom::CSSValue* DoGetOutlineRadiusTopLeft();
-  mozilla::dom::CSSValue* DoGetOutlineRadiusTopRight();
+  already_AddRefed<CSSValue> DoGetOutlineWidth();
+  already_AddRefed<CSSValue> DoGetOutlineStyle();
+  already_AddRefed<CSSValue> DoGetOutlineColor();
+  already_AddRefed<CSSValue> DoGetOutlineOffset();
+  already_AddRefed<CSSValue> DoGetOutlineRadiusBottomLeft();
+  already_AddRefed<CSSValue> DoGetOutlineRadiusBottomRight();
+  already_AddRefed<CSSValue> DoGetOutlineRadiusTopLeft();
+  already_AddRefed<CSSValue> DoGetOutlineRadiusTopRight();
 
   /* Content Properties */
-  mozilla::dom::CSSValue* DoGetContent();
-  mozilla::dom::CSSValue* DoGetCounterIncrement();
-  mozilla::dom::CSSValue* DoGetCounterReset();
-  mozilla::dom::CSSValue* DoGetMarkerOffset();
+  already_AddRefed<CSSValue> DoGetContent();
+  already_AddRefed<CSSValue> DoGetCounterIncrement();
+  already_AddRefed<CSSValue> DoGetCounterReset();
+  already_AddRefed<CSSValue> DoGetMarkerOffset();
 
   /* Quotes Properties */
-  mozilla::dom::CSSValue* DoGetQuotes();
+  already_AddRefed<CSSValue> DoGetQuotes();
 
   /* z-index */
-  mozilla::dom::CSSValue* DoGetZIndex();
+  already_AddRefed<CSSValue> DoGetZIndex();
 
   /* List properties */
-  mozilla::dom::CSSValue* DoGetListStyleImage();
-  mozilla::dom::CSSValue* DoGetListStylePosition();
-  mozilla::dom::CSSValue* DoGetListStyleType();
-  mozilla::dom::CSSValue* DoGetImageRegion();
+  already_AddRefed<CSSValue> DoGetListStyleImage();
+  already_AddRefed<CSSValue> DoGetListStylePosition();
+  already_AddRefed<CSSValue> DoGetListStyleType();
+  already_AddRefed<CSSValue> DoGetImageRegion();
 
   /* Text Properties */
-  mozilla::dom::CSSValue* DoGetLineHeight();
-  mozilla::dom::CSSValue* DoGetRubyAlign();
-  mozilla::dom::CSSValue* DoGetRubyPosition();
-  mozilla::dom::CSSValue* DoGetTextAlign();
-  mozilla::dom::CSSValue* DoGetTextAlignLast();
-  mozilla::dom::CSSValue* DoGetTextCombineUpright();
-  mozilla::dom::CSSValue* DoGetTextDecoration();
-  mozilla::dom::CSSValue* DoGetTextDecorationColor();
-  mozilla::dom::CSSValue* DoGetTextDecorationLine();
-  mozilla::dom::CSSValue* DoGetTextDecorationStyle();
-  mozilla::dom::CSSValue* DoGetTextEmphasisColor();
-  mozilla::dom::CSSValue* DoGetTextEmphasisPosition();
-  mozilla::dom::CSSValue* DoGetTextEmphasisStyle();
-  mozilla::dom::CSSValue* DoGetTextIndent();
-  mozilla::dom::CSSValue* DoGetTextOrientation();
-  mozilla::dom::CSSValue* DoGetTextOverflow();
-  mozilla::dom::CSSValue* DoGetTextTransform();
-  mozilla::dom::CSSValue* DoGetTextShadow();
-  mozilla::dom::CSSValue* DoGetLetterSpacing();
-  mozilla::dom::CSSValue* DoGetWordSpacing();
-  mozilla::dom::CSSValue* DoGetWhiteSpace();
-  mozilla::dom::CSSValue* DoGetWordBreak();
-  mozilla::dom::CSSValue* DoGetWordWrap();
-  mozilla::dom::CSSValue* DoGetHyphens();
-  mozilla::dom::CSSValue* DoGetTabSize();
-  mozilla::dom::CSSValue* DoGetTextSizeAdjust();
+  already_AddRefed<CSSValue> DoGetLineHeight();
+  already_AddRefed<CSSValue> DoGetRubyAlign();
+  already_AddRefed<CSSValue> DoGetRubyPosition();
+  already_AddRefed<CSSValue> DoGetTextAlign();
+  already_AddRefed<CSSValue> DoGetTextAlignLast();
+  already_AddRefed<CSSValue> DoGetTextCombineUpright();
+  already_AddRefed<CSSValue> DoGetTextDecoration();
+  already_AddRefed<CSSValue> DoGetTextDecorationColor();
+  already_AddRefed<CSSValue> DoGetTextDecorationLine();
+  already_AddRefed<CSSValue> DoGetTextDecorationStyle();
+  already_AddRefed<CSSValue> DoGetTextEmphasisColor();
+  already_AddRefed<CSSValue> DoGetTextEmphasisPosition();
+  already_AddRefed<CSSValue> DoGetTextEmphasisStyle();
+  already_AddRefed<CSSValue> DoGetTextIndent();
+  already_AddRefed<CSSValue> DoGetTextOrientation();
+  already_AddRefed<CSSValue> DoGetTextOverflow();
+  already_AddRefed<CSSValue> DoGetTextTransform();
+  already_AddRefed<CSSValue> DoGetTextShadow();
+  already_AddRefed<CSSValue> DoGetLetterSpacing();
+  already_AddRefed<CSSValue> DoGetWordSpacing();
+  already_AddRefed<CSSValue> DoGetWhiteSpace();
+  already_AddRefed<CSSValue> DoGetWordBreak();
+  already_AddRefed<CSSValue> DoGetWordWrap();
+  already_AddRefed<CSSValue> DoGetHyphens();
+  already_AddRefed<CSSValue> DoGetTabSize();
+  already_AddRefed<CSSValue> DoGetTextSizeAdjust();
 
   /* Visibility properties */
-  mozilla::dom::CSSValue* DoGetOpacity();
-  mozilla::dom::CSSValue* DoGetPointerEvents();
-  mozilla::dom::CSSValue* DoGetVisibility();
-  mozilla::dom::CSSValue* DoGetWritingMode();
+  already_AddRefed<CSSValue> DoGetOpacity();
+  already_AddRefed<CSSValue> DoGetPointerEvents();
+  already_AddRefed<CSSValue> DoGetVisibility();
+  already_AddRefed<CSSValue> DoGetWritingMode();
 
   /* Direction properties */
-  mozilla::dom::CSSValue* DoGetDirection();
-  mozilla::dom::CSSValue* DoGetUnicodeBidi();
+  already_AddRefed<CSSValue> DoGetDirection();
+  already_AddRefed<CSSValue> DoGetUnicodeBidi();
 
   /* Display properties */
-  mozilla::dom::CSSValue* DoGetBinding();
-  mozilla::dom::CSSValue* DoGetClear();
-  mozilla::dom::CSSValue* DoGetFloat();
-  mozilla::dom::CSSValue* DoGetDisplay();
-  mozilla::dom::CSSValue* DoGetContain();
-  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* DoGetTransformBox();
-  mozilla::dom::CSSValue* DoGetTransformOrigin();
-  mozilla::dom::CSSValue* DoGetPerspective();
-  mozilla::dom::CSSValue* DoGetBackfaceVisibility();
-  mozilla::dom::CSSValue* DoGetPerspectiveOrigin();
-  mozilla::dom::CSSValue* DoGetTransformStyle();
-  mozilla::dom::CSSValue* DoGetOrient();
-  mozilla::dom::CSSValue* DoGetScrollBehavior();
-  mozilla::dom::CSSValue* DoGetScrollSnapType();
-  mozilla::dom::CSSValue* DoGetScrollSnapTypeX();
-  mozilla::dom::CSSValue* DoGetScrollSnapTypeY();
-  mozilla::dom::CSSValue* DoGetScrollSnapPointsX();
-  mozilla::dom::CSSValue* DoGetScrollSnapPointsY();
-  mozilla::dom::CSSValue* DoGetScrollSnapDestination();
-  mozilla::dom::CSSValue* DoGetScrollSnapCoordinate();
+  already_AddRefed<CSSValue> DoGetBinding();
+  already_AddRefed<CSSValue> DoGetClear();
+  already_AddRefed<CSSValue> DoGetFloat();
+  already_AddRefed<CSSValue> DoGetDisplay();
+  already_AddRefed<CSSValue> DoGetContain();
+  already_AddRefed<CSSValue> DoGetPosition();
+  already_AddRefed<CSSValue> DoGetClip();
+  already_AddRefed<CSSValue> DoGetImageOrientation();
+  already_AddRefed<CSSValue> DoGetWillChange();
+  already_AddRefed<CSSValue> DoGetOverflow();
+  already_AddRefed<CSSValue> DoGetOverflowX();
+  already_AddRefed<CSSValue> DoGetOverflowY();
+  already_AddRefed<CSSValue> DoGetOverflowClipBox();
+  already_AddRefed<CSSValue> DoGetResize();
+  already_AddRefed<CSSValue> DoGetPageBreakAfter();
+  already_AddRefed<CSSValue> DoGetPageBreakBefore();
+  already_AddRefed<CSSValue> DoGetPageBreakInside();
+  already_AddRefed<CSSValue> DoGetTouchAction();
+  already_AddRefed<CSSValue> DoGetTransform();
+  already_AddRefed<CSSValue> DoGetTransformBox();
+  already_AddRefed<CSSValue> DoGetTransformOrigin();
+  already_AddRefed<CSSValue> DoGetPerspective();
+  already_AddRefed<CSSValue> DoGetBackfaceVisibility();
+  already_AddRefed<CSSValue> DoGetPerspectiveOrigin();
+  already_AddRefed<CSSValue> DoGetTransformStyle();
+  already_AddRefed<CSSValue> DoGetOrient();
+  already_AddRefed<CSSValue> DoGetScrollBehavior();
+  already_AddRefed<CSSValue> DoGetScrollSnapType();
+  already_AddRefed<CSSValue> DoGetScrollSnapTypeX();
+  already_AddRefed<CSSValue> DoGetScrollSnapTypeY();
+  already_AddRefed<CSSValue> DoGetScrollSnapPointsX();
+  already_AddRefed<CSSValue> DoGetScrollSnapPointsY();
+  already_AddRefed<CSSValue> DoGetScrollSnapDestination();
+  already_AddRefed<CSSValue> DoGetScrollSnapCoordinate();
 
   /* User interface properties */
-  mozilla::dom::CSSValue* DoGetCursor();
-  mozilla::dom::CSSValue* DoGetForceBrokenImageIcon();
-  mozilla::dom::CSSValue* DoGetIMEMode();
-  mozilla::dom::CSSValue* DoGetUserFocus();
-  mozilla::dom::CSSValue* DoGetUserInput();
-  mozilla::dom::CSSValue* DoGetUserModify();
-  mozilla::dom::CSSValue* DoGetUserSelect();
-  mozilla::dom::CSSValue* DoGetWindowDragging();
+  already_AddRefed<CSSValue> DoGetCursor();
+  already_AddRefed<CSSValue> DoGetForceBrokenImageIcon();
+  already_AddRefed<CSSValue> DoGetIMEMode();
+  already_AddRefed<CSSValue> DoGetUserFocus();
+  already_AddRefed<CSSValue> DoGetUserInput();
+  already_AddRefed<CSSValue> DoGetUserModify();
+  already_AddRefed<CSSValue> DoGetUserSelect();
+  already_AddRefed<CSSValue> DoGetWindowDragging();
 
   /* Column properties */
-  mozilla::dom::CSSValue* DoGetColumnCount();
-  mozilla::dom::CSSValue* DoGetColumnFill();
-  mozilla::dom::CSSValue* DoGetColumnWidth();
-  mozilla::dom::CSSValue* DoGetColumnGap();
-  mozilla::dom::CSSValue* DoGetColumnRuleWidth();
-  mozilla::dom::CSSValue* DoGetColumnRuleStyle();
-  mozilla::dom::CSSValue* DoGetColumnRuleColor();
+  already_AddRefed<CSSValue> DoGetColumnCount();
+  already_AddRefed<CSSValue> DoGetColumnFill();
+  already_AddRefed<CSSValue> DoGetColumnWidth();
+  already_AddRefed<CSSValue> DoGetColumnGap();
+  already_AddRefed<CSSValue> DoGetColumnRuleWidth();
+  already_AddRefed<CSSValue> DoGetColumnRuleStyle();
+  already_AddRefed<CSSValue> DoGetColumnRuleColor();
 
   /* CSS Transitions */
-  mozilla::dom::CSSValue* DoGetTransitionProperty();
-  mozilla::dom::CSSValue* DoGetTransitionDuration();
-  mozilla::dom::CSSValue* DoGetTransitionDelay();
-  mozilla::dom::CSSValue* DoGetTransitionTimingFunction();
+  already_AddRefed<CSSValue> DoGetTransitionProperty();
+  already_AddRefed<CSSValue> DoGetTransitionDuration();
+  already_AddRefed<CSSValue> DoGetTransitionDelay();
+  already_AddRefed<CSSValue> DoGetTransitionTimingFunction();
 
   /* CSS Animations */
-  mozilla::dom::CSSValue* DoGetAnimationName();
-  mozilla::dom::CSSValue* DoGetAnimationDuration();
-  mozilla::dom::CSSValue* DoGetAnimationDelay();
-  mozilla::dom::CSSValue* DoGetAnimationTimingFunction();
-  mozilla::dom::CSSValue* DoGetAnimationDirection();
-  mozilla::dom::CSSValue* DoGetAnimationFillMode();
-  mozilla::dom::CSSValue* DoGetAnimationIterationCount();
-  mozilla::dom::CSSValue* DoGetAnimationPlayState();
+  already_AddRefed<CSSValue> DoGetAnimationName();
+  already_AddRefed<CSSValue> DoGetAnimationDuration();
+  already_AddRefed<CSSValue> DoGetAnimationDelay();
+  already_AddRefed<CSSValue> DoGetAnimationTimingFunction();
+  already_AddRefed<CSSValue> DoGetAnimationDirection();
+  already_AddRefed<CSSValue> DoGetAnimationFillMode();
+  already_AddRefed<CSSValue> DoGetAnimationIterationCount();
+  already_AddRefed<CSSValue> DoGetAnimationPlayState();
 
   /* CSS Flexbox properties */
-  mozilla::dom::CSSValue* DoGetFlexBasis();
-  mozilla::dom::CSSValue* DoGetFlexDirection();
-  mozilla::dom::CSSValue* DoGetFlexGrow();
-  mozilla::dom::CSSValue* DoGetFlexShrink();
-  mozilla::dom::CSSValue* DoGetFlexWrap();
+  already_AddRefed<CSSValue> DoGetFlexBasis();
+  already_AddRefed<CSSValue> DoGetFlexDirection();
+  already_AddRefed<CSSValue> DoGetFlexGrow();
+  already_AddRefed<CSSValue> DoGetFlexShrink();
+  already_AddRefed<CSSValue> DoGetFlexWrap();
 
   /* CSS Flexbox/Grid properties */
-  mozilla::dom::CSSValue* DoGetOrder();
+  already_AddRefed<CSSValue> DoGetOrder();
 
   /* CSS Box Alignment properties */
-  mozilla::dom::CSSValue* DoGetAlignContent();
-  mozilla::dom::CSSValue* DoGetAlignItems();
-  mozilla::dom::CSSValue* DoGetAlignSelf();
-  mozilla::dom::CSSValue* DoGetJustifyContent();
-  mozilla::dom::CSSValue* DoGetJustifyItems();
-  mozilla::dom::CSSValue* DoGetJustifySelf();
+  already_AddRefed<CSSValue> DoGetAlignContent();
+  already_AddRefed<CSSValue> DoGetAlignItems();
+  already_AddRefed<CSSValue> DoGetAlignSelf();
+  already_AddRefed<CSSValue> DoGetJustifyContent();
+  already_AddRefed<CSSValue> DoGetJustifyItems();
+  already_AddRefed<CSSValue> DoGetJustifySelf();
 
   /* SVG properties */
-  mozilla::dom::CSSValue* DoGetFill();
-  mozilla::dom::CSSValue* DoGetStroke();
-  mozilla::dom::CSSValue* DoGetMarkerEnd();
-  mozilla::dom::CSSValue* DoGetMarkerMid();
-  mozilla::dom::CSSValue* DoGetMarkerStart();
-  mozilla::dom::CSSValue* DoGetStrokeDasharray();
+  already_AddRefed<CSSValue> DoGetFill();
+  already_AddRefed<CSSValue> DoGetStroke();
+  already_AddRefed<CSSValue> DoGetMarkerEnd();
+  already_AddRefed<CSSValue> DoGetMarkerMid();
+  already_AddRefed<CSSValue> DoGetMarkerStart();
+  already_AddRefed<CSSValue> DoGetStrokeDasharray();
 
-  mozilla::dom::CSSValue* DoGetStrokeDashoffset();
-  mozilla::dom::CSSValue* DoGetStrokeWidth();
-  mozilla::dom::CSSValue* DoGetVectorEffect();
+  already_AddRefed<CSSValue> DoGetStrokeDashoffset();
+  already_AddRefed<CSSValue> DoGetStrokeWidth();
+  already_AddRefed<CSSValue> DoGetVectorEffect();
 
-  mozilla::dom::CSSValue* DoGetFillOpacity();
-  mozilla::dom::CSSValue* DoGetFloodOpacity();
-  mozilla::dom::CSSValue* DoGetStopOpacity();
-  mozilla::dom::CSSValue* DoGetStrokeMiterlimit();
-  mozilla::dom::CSSValue* DoGetStrokeOpacity();
+  already_AddRefed<CSSValue> DoGetFillOpacity();
+  already_AddRefed<CSSValue> DoGetFloodOpacity();
+  already_AddRefed<CSSValue> DoGetStopOpacity();
+  already_AddRefed<CSSValue> DoGetStrokeMiterlimit();
+  already_AddRefed<CSSValue> DoGetStrokeOpacity();
 
-  mozilla::dom::CSSValue* DoGetClipRule();
-  mozilla::dom::CSSValue* DoGetFillRule();
-  mozilla::dom::CSSValue* DoGetStrokeLinecap();
-  mozilla::dom::CSSValue* DoGetStrokeLinejoin();
-  mozilla::dom::CSSValue* DoGetTextAnchor();
+  already_AddRefed<CSSValue> DoGetClipRule();
+  already_AddRefed<CSSValue> DoGetFillRule();
+  already_AddRefed<CSSValue> DoGetStrokeLinecap();
+  already_AddRefed<CSSValue> DoGetStrokeLinejoin();
+  already_AddRefed<CSSValue> DoGetTextAnchor();
 
-  mozilla::dom::CSSValue* DoGetColorInterpolation();
-  mozilla::dom::CSSValue* DoGetColorInterpolationFilters();
-  mozilla::dom::CSSValue* DoGetDominantBaseline();
-  mozilla::dom::CSSValue* DoGetImageRendering();
-  mozilla::dom::CSSValue* DoGetShapeRendering();
-  mozilla::dom::CSSValue* DoGetTextRendering();
+  already_AddRefed<CSSValue> DoGetColorInterpolation();
+  already_AddRefed<CSSValue> DoGetColorInterpolationFilters();
+  already_AddRefed<CSSValue> DoGetDominantBaseline();
+  already_AddRefed<CSSValue> DoGetImageRendering();
+  already_AddRefed<CSSValue> DoGetShapeRendering();
+  already_AddRefed<CSSValue> DoGetTextRendering();
 
-  mozilla::dom::CSSValue* DoGetFloodColor();
-  mozilla::dom::CSSValue* DoGetLightingColor();
-  mozilla::dom::CSSValue* DoGetStopColor();
+  already_AddRefed<CSSValue> DoGetFloodColor();
+  already_AddRefed<CSSValue> DoGetLightingColor();
+  already_AddRefed<CSSValue> DoGetStopColor();
 
-  mozilla::dom::CSSValue* DoGetClipPath();
-  mozilla::dom::CSSValue* DoGetFilter();
-  mozilla::dom::CSSValue* DoGetMask();
-  mozilla::dom::CSSValue* DoGetMaskType();
-  mozilla::dom::CSSValue* DoGetPaintOrder();
+  already_AddRefed<CSSValue> DoGetClipPath();
+  already_AddRefed<CSSValue> DoGetFilter();
+  already_AddRefed<CSSValue> DoGetMask();
+  already_AddRefed<CSSValue> DoGetMaskType();
+  already_AddRefed<CSSValue> DoGetPaintOrder();
 
   /* Custom properties */
-  mozilla::dom::CSSValue* DoGetCustomProperty(const nsAString& aPropertyName);
+  already_AddRefed<CSSValue> DoGetCustomProperty(const nsAString& aPropertyName);
 
   nsDOMCSSValueList* GetROCSSValueList(bool aCommaDelimited);
 
   /* Helper functions */
   void SetToRGBAColor(nsROCSSPrimitiveValue* aValue, nscolor aColor);
   void SetValueToStyleImage(const nsStyleImage& aStyleImage,
                             nsROCSSPrimitiveValue* aValue);
   void SetValueToPositionCoord(
@@ -602,21 +604,21 @@ private:
   bool GetScrollFrameContentHeight(nscoord& aHeight);
   bool GetFrameBoundsWidthForTransform(nscoord &aWidth);
   bool GetFrameBoundsHeightForTransform(nscoord &aHeight);
   bool GetFrameBorderRectWidth(nscoord& aWidth);
   bool GetFrameBorderRectHeight(nscoord& aHeight);
 
   /* Helper functions for computing the filter property style. */
   void SetCssTextToCoord(nsAString& aCssText, const nsStyleCoord& aCoord);
-  already_AddRefed<mozilla::dom::CSSValue> CreatePrimitiveValueForStyleFilter(
+  already_AddRefed<CSSValue> CreatePrimitiveValueForStyleFilter(
     const nsStyleFilter& aStyleFilter);
 
   // Helper function for computing basic shape styles.
-  mozilla::dom::CSSValue* CreatePrimitiveValueForClipPath(
+  already_AddRefed<CSSValue> CreatePrimitiveValueForClipPath(
     const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox);
   void BoxValuesToString(nsAString& aString,
                          const nsTArray<nsStyleCoord>& aBoxValues);
   void BasicShapeRadiiToString(nsAString& aCssText,
                                const nsStyleCorners& aCorners);
 
 
   static nsComputedStyleMap* GetComputedStyleMap();
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/GLController.java
@@ -81,17 +81,17 @@ public class GLController extends JNIObj
     @WrapForJNI
     private native void pauseCompositor();
 
     // UI thread resumes compositor and notifies Gecko thread; does not block UI thread.
     @WrapForJNI
     private native void syncResumeResizeCompositor(int width, int height);
 
     @WrapForJNI
-    /* package */ native void syncInvalidateAndScheduleComposite();
+    private native void syncInvalidateAndScheduleComposite();
 
     public GLController() {
     }
 
     synchronized void serverSurfaceDestroyed() {
         ThreadUtils.assertOnUiThread();
 
         mServerSurfaceValid = false;
@@ -282,16 +282,22 @@ public class GLController extends JNIObj
         // It is important to not notify Gecko until after the compositor has
         // been resumed, otherwise Gecko may send updates that get dropped.
         if (mCompositorCreated) {
             syncResumeResizeCompositor(width, height);
             mView.requestRender();
         }
     }
 
+    /* package */ void invalidateAndScheduleComposite() {
+        if (mCompositorCreated) {
+            syncInvalidateAndScheduleComposite();
+        }
+    }
+
     public static class GLControllerException extends RuntimeException {
         public static final long serialVersionUID = 1L;
 
         GLControllerException(String e) {
             super(e);
         }
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/java/org/mozilla/gecko/gfx/GeckoLayerClient.java
@@ -1,15 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko.gfx;
 
+import org.mozilla.gecko.annotation.ReflectionTarget;
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.gfx.LayerView.DrawListener;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.ZoomConstraints;
@@ -145,16 +146,18 @@ class GeckoLayerClient implements LayerV
         mPanZoomController.setOverscrollHandler(listener);
     }
 
     /** Attaches to root layer so that Gecko appears. */
     /* package */ boolean isGeckoReady() {
         return mGeckoIsReady;
     }
 
+    // Used by GeckoThread.queueNativeCallUntil through LayerView.onAttachedToWindow.
+    @ReflectionTarget
     public void onGeckoReady() {
         mGeckoIsReady = true;
 
         mRootLayer = new VirtualLayer(new IntSize(mView.getWidth(), mView.getHeight()));
         mLayerRenderer = mView.getRenderer();
 
         sendResizeEventIfNecessary(true, null);
 
@@ -748,17 +751,20 @@ class GeckoLayerClient implements LayerV
         if (getRedrawHint()) {
             adjustViewport(displayPort);
         }
     }
 
     /** Implementation of LayerView.Listener */
     @Override
     public void renderRequested() {
-        mView.getGLController().syncInvalidateAndScheduleComposite();
+        final GLController glController = mView.getGLController();
+        if (glController != null) {
+            glController.invalidateAndScheduleComposite();
+        }
     }
 
     /** Implementation of LayerView.Listener */
     @Override
     public void sizeChanged(int width, int height) {
         // We need to make sure a draw happens synchronously at this point,
         // but resizing the surface before the SurfaceView has resized will
         // cause a visible jump.
--- a/toolkit/components/jsdownloads/test/unit/head.js
+++ b/toolkit/components/jsdownloads/test/unit/head.js
@@ -678,16 +678,24 @@ var gMostRecentFirstBytePos;
 //// Initialization functions common to all tests
 
 add_task(function test_common_initialize()
 {
   // Start the HTTP server.
   gHttpServer = new HttpServer();
   gHttpServer.registerDirectory("/", do_get_file("../data"));
   gHttpServer.start(-1);
+  do_register_cleanup(() => {
+    return new Promise(resolve => {
+      // Ensure all the pending HTTP requests have a chance to finish.
+      continueResponses();
+      // Stop the HTTP server, calling resolve when it's done.
+      gHttpServer.stop(resolve);
+    });
+  });
 
   // Cache locks might prevent concurrent requests to the same resource, and
   // this may block tests that use the interruptible handlers.
   Services.prefs.setBoolPref("browser.cache.disk.enable", false);
   Services.prefs.setBoolPref("browser.cache.memory.enable", false);
   do_register_cleanup(function () {
     Services.prefs.clearUserPref("browser.cache.disk.enable");
     Services.prefs.clearUserPref("browser.cache.memory.enable");
deleted file mode 100644
--- a/toolkit/components/jsdownloads/test/unit/tail.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Provides infrastructure for automated download components tests.
- */
-
-"use strict";
-
-////////////////////////////////////////////////////////////////////////////////
-//// Termination functions common to all tests
-
-add_task(function* test_common_terminate()
-{
-  // Ensure all the pending HTTP requests have a chance to finish.
-  continueResponses();
-
-  // Stop the HTTP server.  We must do this inside a task in "tail.js" until the
-  // xpcshell testing framework supports asynchronous termination functions.
-  let deferred = Promise.defer();
-  gHttpServer.stop(deferred.resolve);
-  yield deferred.promise;
-});
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
@@ -82,14 +82,8 @@ add_task(function test_DownloadError()
 
   error = new DownloadError({ becauseBlockedByParentalControls: true });
   do_check_eq(error.message, "Download blocked.");
   do_check_false(error.becauseSourceFailed);
   do_check_false(error.becauseTargetFailed);
   do_check_true(error.becauseBlocked);
   do_check_true(error.becauseBlockedByParentalControls);
 });
-
-////////////////////////////////////////////////////////////////////////////////
-//// Termination
-
-var tailFile = do_get_file("tail.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(tailFile).spec);
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
@@ -410,14 +410,8 @@ add_task(function* test_exit_private_bro
   Services.obs.notifyObservers(null, "last-pb-context-exited", null);
   let result = yield DownloadIntegration._deferTestClearPrivateList.promise;
 
   do_check_eq(result, "success");
   do_check_eq((yield privateList.getAll()).length, 0);
 
   continueResponses();
 });
-
-////////////////////////////////////////////////////////////////////////////////
-//// Termination
-
-var tailFile = do_get_file("tail.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(tailFile).spec);
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js
@@ -11,14 +11,8 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Execution of common tests
 
 var gUseLegacySaver = true;
 
 var scriptFile = do_get_file("common_test_Download.js");
 Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
-
-////////////////////////////////////////////////////////////////////////////////
-//// Termination
-
-var tailFile = do_get_file("tail.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(tailFile).spec);
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
@@ -559,14 +559,8 @@ add_task(function* test_DownloadSummary_
   yield summary.addView({
     onSummaryChanged: function () {
       receivedOnSummaryChanged = true;
     },
   });
   yield download.start();
   do_check_true(receivedOnSummaryChanged);
 });
-
-////////////////////////////////////////////////////////////////////////////////
-//// Termination
-
-var tailFile = do_get_file("tail.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(tailFile).spec);
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
@@ -300,14 +300,8 @@ add_task(function* test_save_reload_unkn
               "download3target2");
 
   do_check_eq(Object.keys(itemsForLoad[2].saver._unknownProperties).length, 2);
   do_check_eq(itemsForLoad[2].saver._unknownProperties.saver1,
               "download3saver1");
   do_check_eq(itemsForLoad[2].saver._unknownProperties.saver2,
               "download3saver2");
 });
-
-////////////////////////////////////////////////////////////////////////////////
-//// Termination
-
-var tailFile = do_get_file("tail.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(tailFile).spec);
--- a/toolkit/components/jsdownloads/test/unit/test_Downloads.js
+++ b/toolkit/components/jsdownloads/test/unit/test_Downloads.js
@@ -188,14 +188,8 @@ add_task(function* test_getPreferredDown
  * Tests that the getTemporaryDownloadsDirectory returns a non-empty download
  * directory string.
  */
 add_task(function* test_getTemporaryDownloadsDirectory()
 {
   let downloadDir = yield Downloads.getTemporaryDownloadsDirectory();
   do_check_neq(downloadDir, "");
 });
-
-////////////////////////////////////////////////////////////////////////////////
-//// Termination
-
-var tailFile = do_get_file("tail.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(tailFile).spec);
--- a/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
+++ b/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
@@ -17,16 +17,8 @@ add_task(function* test_private_temp() {
   yield promiseDownloadStopped(download);
 
   var targetFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
   targetFile.initWithPath(download.target.path);
 
   // 488 is the decimal value of 0700.
   equal(targetFile.parent.permissions, 448);
 });
-
-
-////////////////////////////////////////////////////////////////////////////////
-//// Termination
-
-var tailFile = do_get_file("tail.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(tailFile).spec);
-
--- a/toolkit/components/jsdownloads/test/unit/xpcshell.ini
+++ b/toolkit/components/jsdownloads/test/unit/xpcshell.ini
@@ -2,17 +2,16 @@
 head = head.js
 tail =
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 # Note: The "tail.js" file is not defined in the "tail" key because it calls
 #       the "add_test_task" function, that does not work properly in tail files.
 support-files =
   common_test_Download.js
-  tail.js
 
 [test_DownloadCore.js]
 [test_DownloadImport.js]
 [test_DownloadIntegration.js]
 [test_DownloadLegacy.js]
 [test_DownloadList.js]
 [test_Downloads.js]
 [test_DownloadStore.js]