Merge inbound to m-c on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 03 Feb 2014 18:08:45 -0500
changeset 166644 23555d9a4a17d8a7e1786224bbcd0276c63f268d
parent 166631 f10b3ebdc7566c55beb83c054cea550f9571ce1d (current diff)
parent 166643 ad62bf4d62b4e3f8a652de98082fe61cfb61685f (diff)
child 166673 c150845d077dce845023d4c3708c1ebbbc1e2816
push id4808
push userryanvm@gmail.com
push dateMon, 03 Feb 2014 23:16:15 +0000
treeherderfx-team@c150845d077d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.0a1
Merge inbound to m-c on a CLOSED TREE.
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1992,17 +1992,18 @@ public:
            mozilla::ErrorResult& rv) = 0;
   already_AddRefed<nsContentList>
   GetElementsByTagName(const nsAString& aTagName)
   {
     return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName);
   }
   already_AddRefed<nsContentList>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
-                           const nsAString& aLocalName);
+                           const nsAString& aLocalName,
+                           mozilla::ErrorResult& aResult);
   already_AddRefed<nsContentList>
     GetElementsByClassName(const nsAString& aClasses);
   // GetElementById defined above
   already_AddRefed<Element> CreateElement(const nsAString& aTagName,
                                           mozilla::ErrorResult& rv);
   already_AddRefed<Element> CreateElementNS(const nsAString& aNamespaceURI,
                                             const nsAString& aQualifiedName,
                                             mozilla::ErrorResult& rv);
--- a/content/base/src/Link.cpp
+++ b/content/base/src/Link.cpp
@@ -212,19 +212,17 @@ Link::SetPathname(const nsAString &aPath
   (void)url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
   SetHrefAttribute(uri);
 }
 
 void
 Link::SetSearch(const nsAString& aSearch)
 {
   SetSearchInternal(aSearch);
-  if (mSearchParams) {
-    mSearchParams->Invalidate();
-  }
+  UpdateURLSearchParams();
 }
 
 void
 Link::SetSearchInternal(const nsAString& aSearch)
 {
   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   if (!url) {
@@ -482,19 +480,17 @@ Link::ResetLinkState(bool aNotify, bool 
     UnregisterFromHistory();
   }
 
   // If we have an href, we should register with the history.
   mNeedsRegistration = aHasHref;
 
   // If we've cached the URI, reset always invalidates it.
   mCachedURI = nullptr;
-  if (mSearchParams) {
-    mSearchParams->Invalidate();
-  }
+  UpdateURLSearchParams();
 
   // Update our state back to the default.
   mLinkState = defaultState;
 
   // We have to be very careful here: if aNotify is false we do NOT
   // want to call UpdateState, because that will call into LinkState()
   // and try to start off loads, etc.  But ResetLinkState is called
   // with aNotify false when things are in inconsistent states, so
@@ -584,66 +580,65 @@ Link::GetSearchParams()
 
 void
 Link::SetSearchParams(URLSearchParams* aSearchParams)
 {
   if (!aSearchParams) {
     return;
   }
 
-  if (!aSearchParams->HasURLAssociated()) {
-    MOZ_ASSERT(aSearchParams->IsValid());
+  if (mSearchParams) {
+    mSearchParams->RemoveObserver(this);
+  }
 
-    mSearchParams = aSearchParams;
-    mSearchParams->SetObserver(this);
-  } else {
-    CreateSearchParamsIfNeeded();
-    mSearchParams->CopyFromURLSearchParams(*aSearchParams);
-  }
+  mSearchParams = aSearchParams;
+  mSearchParams->AddObserver(this);
 
   nsAutoString search;
   mSearchParams->Serialize(search);
   SetSearchInternal(search);
 }
 
 void
 Link::URLSearchParamsUpdated()
 {
-  MOZ_ASSERT(mSearchParams && mSearchParams->IsValid());
+  MOZ_ASSERT(mSearchParams);
 
   nsString search;
   mSearchParams->Serialize(search);
   SetSearchInternal(search);
 }
 
 void
-Link::URLSearchParamsNeedsUpdates()
+Link::UpdateURLSearchParams()
 {
-  MOZ_ASSERT(mSearchParams);
+  if (!mSearchParams) {
+    return;
+  }
 
   nsAutoCString search;
   nsCOMPtr<nsIURI> uri(GetURI());
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   if (url) {
     nsresult rv = url->GetQuery(search);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to get the query from a nsIURL.");
     }
   }
 
-  mSearchParams->ParseInput(search);
+  mSearchParams->ParseInput(search, this);
 }
 
 void
 Link::CreateSearchParamsIfNeeded()
 {
   if (!mSearchParams) {
     mSearchParams = new URLSearchParams();
-    mSearchParams->SetObserver(this);
-    mSearchParams->Invalidate();
+    mSearchParams->AddObserver(this);
+    UpdateURLSearchParams();
   }
 }
 
 void
 Link::Unlink()
 {
   mSearchParams = nullptr;
 }
--- a/content/base/src/Link.h
+++ b/content/base/src/Link.h
@@ -109,17 +109,16 @@ public:
 
   virtual size_t
     SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   bool ElementHasHref() const;
 
   // URLSearchParamsObserver
   void URLSearchParamsUpdated() MOZ_OVERRIDE;
-  void URLSearchParamsNeedsUpdates() MOZ_OVERRIDE;
 
 protected:
   virtual ~Link();
 
   /**
    * Return true if the link has associated URI.
    */
   bool HasURI() const
@@ -129,16 +128,18 @@ protected:
     }
 
     return !!GetURI();
   }
 
   nsIURI* GetCachedURI() const { return mCachedURI; }
   bool HasCachedURI() const { return !!mCachedURI; }
 
+  void UpdateURLSearchParams();
+
   // CC methods
   void Unlink();
   void Traverse(nsCycleCollectionTraversalCallback &cb);
 
 private:
   /**
    * Unregisters from History so this node no longer gets notifications about
    * changes to visitedness.
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -5398,40 +5398,46 @@ nsDocument::GetElementsByTagName(const n
 
   // transfer ref to aReturn
   *aReturn = list.forget().get();
   return NS_OK;
 }
 
 already_AddRefed<nsContentList>
 nsIDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
-                                    const nsAString& aLocalName)
+                                    const nsAString& aLocalName,
+                                    ErrorResult& aResult)
 {
   int32_t nameSpaceId = kNameSpaceID_Wildcard;
 
   if (!aNamespaceURI.EqualsLiteral("*")) {
-    nsresult rv =
+    aResult =
       nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
                                                             nameSpaceId);
-    NS_ENSURE_SUCCESS(rv, nullptr);
+    if (aResult.Failed()) {
+      return nullptr;
+    }
   }
 
   NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
 
   return NS_GetContentList(this, nameSpaceId, aLocalName);
 }
 
 NS_IMETHODIMP
 nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                                    const nsAString& aLocalName,
                                    nsIDOMNodeList** aReturn)
 {
+  ErrorResult rv;
   nsRefPtr<nsContentList> list =
-    nsIDocument::GetElementsByTagNameNS(aNamespaceURI, aLocalName);
-  NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
+    nsIDocument::GetElementsByTagNameNS(aNamespaceURI, aLocalName, rv);
+  if (rv.Failed()) {
+    return rv.ErrorCode();
+  }
 
   // transfer ref to aReturn
   *aReturn = list.forget().get();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::GetAsync(bool *aAsync)
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -216,20 +216,17 @@ URL::SetHref(const nsAString& aHref, Err
   rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri));
   if (NS_FAILED(rv)) {
     nsAutoString label(aHref);
     aRv.ThrowTypeError(MSG_INVALID_URL, &label);
     return;
   }
 
   aRv = mURI->SetSpec(href);
-
-  if (mSearchParams) {
-    mSearchParams->Invalidate();
-  }
+  UpdateURLSearchParams();
 }
 
 void
 URL::GetOrigin(nsString& aOrigin) const
 {
   nsContentUtils::GetUTFNonNullOrigin(mURI, aOrigin);
 }
 
@@ -299,38 +296,40 @@ void
 URL::SetHost(const nsAString& aHost)
 {
   mURI->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
 }
 
 void
 URL::URLSearchParamsUpdated()
 {
-  MOZ_ASSERT(mSearchParams && mSearchParams->IsValid());
+  MOZ_ASSERT(mSearchParams);
 
   nsAutoString search;
   mSearchParams->Serialize(search);
   SetSearchInternal(search);
 }
 
 void
-URL::URLSearchParamsNeedsUpdates()
+URL::UpdateURLSearchParams()
 {
-  MOZ_ASSERT(mSearchParams);
+  if (!mSearchParams) {
+    return;
+  }
 
   nsAutoCString search;
   nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
   if (url) {
     nsresult rv = url->GetQuery(search);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to get the query from a nsIURL.");
     }
   }
 
-  mSearchParams->ParseInput(search);
+  mSearchParams->ParseInput(search, this);
 }
 
 void
 URL::GetHostname(nsString& aHostname) const
 {
   URL_GETTER(aHostname, GetHost);
 }
 
@@ -421,20 +420,17 @@ URL::GetSearch(nsString& aSearch) const
     CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
   }
 }
 
 void
 URL::SetSearch(const nsAString& aSearch)
 {
   SetSearchInternal(aSearch);
-
-  if (mSearchParams) {
-    mSearchParams->Invalidate();
-  }
+  UpdateURLSearchParams();
 }
 
 void
 URL::SetSearchInternal(const nsAString& aSearch)
 {
   nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
   if (!url) {
     // Ignore failures to be compatible with NS4.
@@ -453,25 +449,23 @@ URL::GetSearchParams()
 
 void
 URL::SetSearchParams(URLSearchParams* aSearchParams)
 {
   if (!aSearchParams) {
     return;
   }
 
-  if (!aSearchParams->HasURLAssociated()) {
-    MOZ_ASSERT(aSearchParams->IsValid());
+  if (mSearchParams) {
+    mSearchParams->RemoveObserver(this);
+  }
 
-    mSearchParams = aSearchParams;
-    mSearchParams->SetObserver(this);
-  } else {
-    CreateSearchParamsIfNeeded();
-    mSearchParams->CopyFromURLSearchParams(*aSearchParams);
-  }
+  // the observer will be cleared using the cycle collector.
+  mSearchParams = aSearchParams;
+  mSearchParams->AddObserver(this);
 
   nsAutoString search;
   mSearchParams->Serialize(search);
   SetSearchInternal(search);
 }
 
 void
 URL::GetHash(nsString& aHash) const
@@ -501,15 +495,15 @@ bool IsChromeURI(nsIURI* aURI)
   return false;
 }
 
 void
 URL::CreateSearchParamsIfNeeded()
 {
   if (!mSearchParams) {
     mSearchParams = new URLSearchParams();
-    mSearchParams->SetObserver(this);
-    mSearchParams->Invalidate();
+    mSearchParams->AddObserver(this);
+    UpdateURLSearchParams();
   }
 }
 
 }
 }
--- a/dom/base/URL.h
+++ b/dom/base/URL.h
@@ -120,28 +120,29 @@ public:
 
   void Stringify(nsString& aRetval) const
   {
     GetHref(aRetval);
   }
 
   // URLSearchParamsObserver
   void URLSearchParamsUpdated() MOZ_OVERRIDE;
-  void URLSearchParamsNeedsUpdates() MOZ_OVERRIDE;
 
 private:
   nsIURI* GetURI() const
   {
     return mURI;
   }
 
   void CreateSearchParamsIfNeeded();
 
   void SetSearchInternal(const nsAString& aSearch);
 
+  void UpdateURLSearchParams();
+
   static void CreateObjectURLInternal(const GlobalObject& aGlobal,
                                       nsISupports* aObject,
                                       const nsACString& aScheme,
                                       const objectURLOptions& aOptions,
                                       nsString& aResult,
                                       ErrorResult& aError);
 
   nsCOMPtr<nsIURI> mURI;
--- a/dom/base/URLSearchParams.cpp
+++ b/dom/base/URLSearchParams.cpp
@@ -4,27 +4,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "URLSearchParams.h"
 #include "mozilla/dom/URLSearchParamsBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(URLSearchParams, mObserver)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(URLSearchParams, mObservers)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URLSearchParams)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 URLSearchParams::URLSearchParams()
-  : mValid(false)
 {
   SetIsDOMBinding();
 }
 
 URLSearchParams::~URLSearchParams()
 {
   DeleteAll();
 }
@@ -36,33 +35,33 @@ URLSearchParams::WrapObject(JSContext* a
 }
 
 /* static */ already_AddRefed<URLSearchParams>
 URLSearchParams::Constructor(const GlobalObject& aGlobal,
                              const nsAString& aInit,
                              ErrorResult& aRv)
 {
   nsRefPtr<URLSearchParams> sp = new URLSearchParams();
-  sp->ParseInput(NS_ConvertUTF16toUTF8(aInit));
+  sp->ParseInput(NS_ConvertUTF16toUTF8(aInit), nullptr);
   return sp.forget();
 }
 
 /* static */ already_AddRefed<URLSearchParams>
 URLSearchParams::Constructor(const GlobalObject& aGlobal,
                              URLSearchParams& aInit,
                              ErrorResult& aRv)
 {
   nsRefPtr<URLSearchParams> sp = new URLSearchParams();
   aInit.mSearchParams.EnumerateRead(CopyEnumerator, sp);
-  sp->mValid = true;
   return sp.forget();
 }
 
 void
-URLSearchParams::ParseInput(const nsACString& aInput)
+URLSearchParams::ParseInput(const nsACString& aInput,
+                            URLSearchParamsObserver* aObserver)
 {
   // Remove all the existing data before parsing a new input.
   DeleteAll();
 
   nsACString::const_iterator start, end;
   aInput.BeginReading(start);
   aInput.EndReading(end);
   nsACString::const_iterator iter(start);
@@ -104,17 +103,17 @@ URLSearchParams::ParseInput(const nsACSt
 
     nsAutoCString decodedValue;
     DecodeString(value, decodedValue);
 
     AppendInternal(NS_ConvertUTF8toUTF16(decodedName),
                    NS_ConvertUTF8toUTF16(decodedValue));
   }
 
-  mValid = true;
+  NotifyObservers(aObserver);
 }
 
 void
 URLSearchParams::DecodeString(const nsACString& aInput, nsACString& aOutput)
 {
   nsACString::const_iterator start, end;
   aInput.BeginReading(start);
   aInput.EndReading(end);
@@ -160,114 +159,89 @@ URLSearchParams::DecodeString(const nsAC
       }
     }
 
     aOutput.Append(*start);
     ++start;
   }
 }
 
-void
-URLSearchParams::CopyFromURLSearchParams(URLSearchParams& aSearchParams)
-{
-  // The other SearchParams must be valid before copying its data.
-  aSearchParams.Validate();
-
-  // Remove all the existing data before parsing a new input.
-  DeleteAll();
-  aSearchParams.mSearchParams.EnumerateRead(CopyEnumerator, this);
-  mValid = true;
-}
-
 /* static */ PLDHashOperator
 URLSearchParams::CopyEnumerator(const nsAString& aName,
                                 nsTArray<nsString>* aArray,
                                 void *userData)
 {
   URLSearchParams* aSearchParams = static_cast<URLSearchParams*>(userData);
 
   nsTArray<nsString>* newArray = new nsTArray<nsString>();
   newArray->AppendElements(*aArray);
 
   aSearchParams->mSearchParams.Put(aName, newArray);
   return PL_DHASH_NEXT;
 }
 
 void
-URLSearchParams::SetObserver(URLSearchParamsObserver* aObserver)
+URLSearchParams::AddObserver(URLSearchParamsObserver* aObserver)
 {
-  MOZ_ASSERT(!mObserver);
-  mObserver = aObserver;
+  MOZ_ASSERT(aObserver);
+  MOZ_ASSERT(!mObservers.Contains(aObserver));
+  mObservers.AppendElement(aObserver);
 }
 
 void
-URLSearchParams::Validate()
+URLSearchParams::RemoveObserver(URLSearchParamsObserver* aObserver)
 {
-  MOZ_ASSERT(mValid || mObserver);
-  if (!mValid) {
-    mObserver->URLSearchParamsNeedsUpdates();
-    MOZ_ASSERT(mValid);
-  }
+  MOZ_ASSERT(aObserver);
+  MOZ_ASSERT(mObservers.Contains(aObserver));
+  mObservers.RemoveElement(aObserver);
 }
 
 void
 URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
 {
-  Validate();
-
   nsTArray<nsString>* array;
   if (!mSearchParams.Get(aName, &array)) {
     aRetval.Truncate();
     return;
   }
 
   aRetval.Assign(array->ElementAt(0));
 }
 
 void
 URLSearchParams::GetAll(const nsAString& aName, nsTArray<nsString>& aRetval)
 {
-  Validate();
-
   nsTArray<nsString>* array;
   if (!mSearchParams.Get(aName, &array)) {
     return;
   }
 
   aRetval.AppendElements(*array);
 }
 
 void
 URLSearchParams::Set(const nsAString& aName, const nsAString& aValue)
 {
-  // Before setting any new value we have to be sure to have all the previous
-  // values in place.
-  Validate();
-
   nsTArray<nsString>* array;
   if (!mSearchParams.Get(aName, &array)) {
     array = new nsTArray<nsString>();
     array->AppendElement(aValue);
     mSearchParams.Put(aName, array);
   } else {
     array->ElementAt(0) = aValue;
   }
 
-  NotifyObserver();
+  NotifyObservers(nullptr);
 }
 
 void
 URLSearchParams::Append(const nsAString& aName, const nsAString& aValue)
 {
-  // Before setting any new value we have to be sure to have all the previous
-  // values in place.
-  Validate();
-
   AppendInternal(aName, aValue);
-  NotifyObserver();
+  NotifyObservers(nullptr);
 }
 
 void
 URLSearchParams::AppendInternal(const nsAString& aName, const nsAString& aValue)
 {
   nsTArray<nsString>* array;
   if (!mSearchParams.Get(aName, &array)) {
     array = new nsTArray<nsString>();
@@ -275,35 +249,30 @@ URLSearchParams::AppendInternal(const ns
   }
 
   array->AppendElement(aValue);
 }
 
 bool
 URLSearchParams::Has(const nsAString& aName)
 {
-  Validate();
   return mSearchParams.Get(aName, nullptr);
 }
 
 void
 URLSearchParams::Delete(const nsAString& aName)
 {
-  // Before deleting any value we have to be sure to have all the previous
-  // values in place.
-  Validate();
-
   nsTArray<nsString>* array;
   if (!mSearchParams.Get(aName, &array)) {
     return;
   }
 
   mSearchParams.Remove(aName);
 
-  NotifyObserver();
+  NotifyObservers(nullptr);
 }
 
 void
 URLSearchParams::DeleteAll()
 {
   mSearchParams.Clear();
 }
 
@@ -338,18 +307,16 @@ public:
       ++p;
     }
   }
 };
 
 void
 URLSearchParams::Serialize(nsAString& aValue) const
 {
-  MOZ_ASSERT(mValid);
-
   SerializeData data;
   mSearchParams.EnumerateRead(SerializeEnumerator, &data);
   aValue.Assign(data.mValue);
 }
 
 /* static */ PLDHashOperator
 URLSearchParams::SerializeEnumerator(const nsAString& aName,
                                      nsTArray<nsString>* aArray,
@@ -368,23 +335,19 @@ URLSearchParams::SerializeEnumerator(con
     data->mValue.Append(NS_LITERAL_STRING("="));
     data->Serialize(NS_ConvertUTF16toUTF8(aArray->ElementAt(i)));
   }
 
   return PL_DHASH_NEXT;
 }
 
 void
-URLSearchParams::NotifyObserver()
+URLSearchParams::NotifyObservers(URLSearchParamsObserver* aExceptObserver)
 {
-  if (mObserver) {
-    mObserver->URLSearchParamsUpdated();
+  for (uint32_t i = 0; i < mObservers.Length(); ++i) {
+    if (mObservers[i] != aExceptObserver) {
+      mObservers[i]->URLSearchParamsUpdated();
+    }
   }
 }
 
-void
-URLSearchParams::Invalidate()
-{
-  mValid = false;
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/URLSearchParams.h
+++ b/dom/base/URLSearchParams.h
@@ -18,34 +18,28 @@ namespace mozilla {
 namespace dom {
 
 class URLSearchParamsObserver : public nsISupports
 {
 public:
   virtual ~URLSearchParamsObserver() {}
 
   virtual void URLSearchParamsUpdated() = 0;
-  virtual void URLSearchParamsNeedsUpdates() = 0;
 };
 
 class URLSearchParams MOZ_FINAL : public nsISupports,
                                   public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(URLSearchParams)
 
   URLSearchParams();
   ~URLSearchParams();
 
-  bool HasURLAssociated() const
-  {
-    return !!mObserver;
-  }
-
   // WebIDL methods
   nsISupports* GetParentObject() const
   {
     return nullptr;
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
@@ -53,28 +47,21 @@ public:
   static already_AddRefed<URLSearchParams>
   Constructor(const GlobalObject& aGlobal, const nsAString& aInit,
               ErrorResult& aRv);
 
   static already_AddRefed<URLSearchParams>
   Constructor(const GlobalObject& aGlobal, URLSearchParams& aInit,
               ErrorResult& aRv);
 
-  void ParseInput(const nsACString& aInput);
-
-  void CopyFromURLSearchParams(URLSearchParams& aSearchParams);
-
-  void SetObserver(URLSearchParamsObserver* aObserver);
+  void ParseInput(const nsACString& aInput,
+                  URLSearchParamsObserver* aObserver);
 
-  void Invalidate();
-
-  bool IsValid() const
-  {
-    return mValid;
-  }
+  void AddObserver(URLSearchParamsObserver* aObserver);
+  void RemoveObserver(URLSearchParamsObserver* aObserver);
 
   void Serialize(nsAString& aValue) const;
 
   void Get(const nsAString& aName, nsString& aRetval);
 
   void GetAll(const nsAString& aName, nsTArray<nsString >& aRetval);
 
   void Set(const nsAString& aName, const nsAString& aValue);
@@ -82,43 +69,37 @@ public:
   void Append(const nsAString& aName, const nsAString& aValue);
 
   bool Has(const nsAString& aName);
 
   void Delete(const nsAString& aName);
 
   void Stringify(nsString& aRetval)
   {
-    Validate();
     Serialize(aRetval);
   }
 
 private:
   void AppendInternal(const nsAString& aName, const nsAString& aValue);
 
   void DeleteAll();
 
   void DecodeString(const nsACString& aInput, nsACString& aOutput);
 
-  void NotifyObserver();
+  void NotifyObservers(URLSearchParamsObserver* aExceptObserver);
 
   static PLDHashOperator
   CopyEnumerator(const nsAString& aName, nsTArray<nsString>* aArray,
                  void *userData);
 
   static PLDHashOperator
   SerializeEnumerator(const nsAString& aName, nsTArray<nsString>* aArray,
                       void *userData);
 
-  void
-  Validate();
-
   nsClassHashtable<nsStringHashKey, nsTArray<nsString>> mSearchParams;
 
-  nsRefPtr<URLSearchParamsObserver> mObserver;
-
-  bool mValid;
+  nsTArray<nsRefPtr<URLSearchParamsObserver>> mObservers;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_URLSearchParams_h */
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -233,16 +233,26 @@ KillTimers()
   nsJSContext::KillGCTimer();
   nsJSContext::KillShrinkGCBuffersTimer();
   nsJSContext::KillCCTimer();
   nsJSContext::KillICCTimer();
   nsJSContext::KillFullGCTimer();
   nsJSContext::KillInterSliceGCTimer();
 }
 
+// If we collected a substantial amount of cycles, poke the GC since more objects
+// might be unreachable now.
+static bool
+NeedsGCAfterCC()
+{
+  return sCCollectedWaitingForGC > 250 ||
+    sLikelyShortLivingObjectsNeedingGC > 2500 ||
+    sNeedsGCAfterCC;
+}
+
 class nsJSEnvironmentObserver MOZ_FINAL : public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 };
 
 NS_IMPL_ISUPPORTS1(nsJSEnvironmentObserver, nsIObserver)
@@ -258,16 +268,22 @@ nsJSEnvironmentObserver::Observe(nsISupp
       // slow and it likely won't help us anyway.
       return NS_OK;
     }
     nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
                                    nsJSContext::NonIncrementalGC,
                                    nsJSContext::NonCompartmentGC,
                                    nsJSContext::ShrinkingGC);
     nsJSContext::CycleCollectNow();
+    if (NeedsGCAfterCC()) {
+      nsJSContext::GarbageCollectNow(JS::gcreason::MEM_PRESSURE,
+                                     nsJSContext::NonIncrementalGC,
+                                     nsJSContext::NonCompartmentGC,
+                                     nsJSContext::ShrinkingGC);
+    }
   } else if (!nsCRT::strcmp(aTopic, "quit-application")) {
     sShuttingDown = true;
     KillTimers();
   }
 
   return NS_OK;
 }
 
@@ -2210,21 +2226,17 @@ nsJSContext::EndCycleCollectionCallback(
 
   nsJSContext::KillICCTimer();
 
   // Update timing information for the current slice before we log it.
   gCCStats.FinishCycleCollectionSlice();
 
   sCCollectedWaitingForGC += aResults.mFreedRefCounted + aResults.mFreedGCed;
 
-  // If we collected a substantial amount of cycles, poke the GC since more objects
-  // might be unreachable now.
-  if (sCCollectedWaitingForGC > 250 ||
-      sLikelyShortLivingObjectsNeedingGC > 2500 ||
-      sNeedsGCAfterCC) {
+  if (NeedsGCAfterCC()) {
     PokeGC(JS::gcreason::CC_WAITING);
   }
 
   TimeStamp endCCTime = TimeStamp::Now();
 
   // Log information about the CC via telemetry, JSON and the console.
   uint32_t ccNowDuration = TimeBetween(gCCStats.mBeginTime, endCCTime);
   Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC, gCCStats.mAnyLockedOut);
--- a/dom/base/test/test_urlSearchParams.html
+++ b/dom/base/test/test_urlSearchParams.html
@@ -132,17 +132,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(url.href, 'http://www.example.net/?foo=bar', 'URL right');
 
     url.searchParams = null;
     is(url.searchParams.get('foo'), 'bar', "URL.searchParams.get('foo')");
     is(url.href, 'http://www.example.net/?foo=bar', 'URL right');
 
     var url2 = new URL('http://www.example.net?e=f');
     url.searchParams = url2.searchParams;
-    isnot(url.searchParams, url2.searchParams, "URL.searchParams is not the same object");
+    is(url.searchParams, url2.searchParams, "URL.searchParams is not the same object");
     is(url.searchParams.get('e'), 'f', "URL.searchParams.get('e')");
 
     url.href = "http://www.example.net?bar=foo";
     is(url.searchParams.get('bar'), 'foo', "URL.searchParams.get('bar')");
 
     runTest();
   }
 
@@ -165,17 +165,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(e.href, 'http://www.example.net/?foo=bar', 'e is right');
 
     e.searchParams = null;
     is(e.searchParams.get('foo'), 'bar', "e.searchParams.get('foo')");
     is(e.href, 'http://www.example.net/?foo=bar', 'e is right');
 
     var url2 = new URL('http://www.example.net?e=f');
     e.searchParams = url2.searchParams;
-    isnot(e.searchParams, url2.searchParams, "e.searchParams is not the same object");
+    is(e.searchParams, url2.searchParams, "e.searchParams is not the same object");
     is(e.searchParams.get('e'), 'f', "e.searchParams.get('e')");
 
     e.href = "http://www.example.net?bar=foo";
     is(e.searchParams.get('bar'), 'foo', "e.searchParams.get('bar')");
 
     e.setAttribute('href', "http://www.example.net?bar2=foo2");
     is(e.searchParams.get('bar2'), 'foo2', "e.searchParams.get('bar2')");
 
@@ -198,24 +198,64 @@ https://bugzilla.mozilla.org/show_bug.cg
 
       var url2 = new URL(url.href);
       is(url2.searchParams.get('a'), encoding[i][0], 'a is still there');
     }
 
     runTest();
   }
 
+  function testMultiURL() {
+    var a = new URL('http://www.example.net?a=b&c=d');
+    var b = new URL('http://www.example.net?e=f');
+    var c = document.createElement('a');
+    var d = document.createElement('area');
+    ok(a.searchParams.has('a'), "a.searchParams.has('a')");
+    ok(a.searchParams.has('c'), "a.searchParams.has('c')");
+    ok(b.searchParams.has('e'), "b.searchParams.has('e')");
+    ok(c.searchParams, "c.searchParams");
+    ok(d.searchParams, "d.searchParams");
+
+    var u = new URLSearchParams();
+    a.searchParams = b.searchParams = c.searchParams = d.searchParams = u;
+    is(a.searchParams, u, "a.searchParams === u");
+    is(b.searchParams, u, "b.searchParams === u");
+    is(c.searchParams, u, "c.searchParams === u");
+    is(d.searchParams, u, "d.searchParams === u");
+    ok(!a.searchParams.has('a'), "!a.searchParams.has('a')");
+    ok(!a.searchParams.has('c'), "!a.searchParams.has('c')");
+    ok(!b.searchParams.has('e'), "!b.searchParams.has('e')");
+
+    u.append('foo', 'bar');
+    is(a.searchParams.get('foo'), 'bar', "a has foo=bar");
+    is(b.searchParams.get('foo'), 'bar', "b has foo=bar");
+    is(c.searchParams.get('foo'), 'bar', "c has foo=bar");
+    is(d.searchParams.get('foo'), 'bar', "d has foo=bar");
+    is(a + "", b + "", "stringify a == b");
+    is(c.searchParams + "", b.searchParams + "", "stringify c.searchParams == b.searchParams");
+    is(d.searchParams + "", b.searchParams + "", "stringify d.searchParams == b.searchParams");
+
+    a.search = "?bar=foo";
+    is(a.searchParams.get('bar'), 'foo', "a has bar=foo");
+    is(b.searchParams.get('bar'), 'foo', "b has bar=foo");
+    is(c.searchParams.get('bar'), 'foo', "c has bar=foo");
+    is(d.searchParams.get('bar'), 'foo', "d has bar=foo");
+
+    runTest();
+  }
+
   var tests = [
     testSimpleURLSearchParams,
     testCopyURLSearchParams,
     testParserURLSearchParams,
     testURL,
     function() { testElement(document.getElementById('anchor')) },
     function() { testElement(document.getElementById('area')) },
-    testEncoding
+    testEncoding,
+    testMultiURL
   ];
 
   function runTest() {
     if (!tests.length) {
       SimpleTest.finish();
       return;
     }
 
--- a/dom/bindings/test/mochitest.ini
+++ b/dom/bindings/test/mochitest.ini
@@ -27,10 +27,11 @@ support-files =
 [test_integers.html]
 [test_interfaceToString.html]
 [test_exceptions_from_jsimplemented.html]
 [test_lenientThis.html]
 [test_lookupGetter.html]
 [test_namedNoIndexed.html]
 [test_queryInterface.html]
 [test_sequence_wrapping.html]
+[test_throwing_method_noDCE.html]
 [test_treat_non_object_as_null.html]
 [test_traceProtos.html]
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_throwing_method_noDCE.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test that we don't DCE functions that can throw</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+  function test(root) {
+    var threw = false;
+    try {
+        root.querySelectorAll("");
+    } catch(e){ threw = true; };
+    // Hot loop to make sure the JIT heuristics ion-compile this function even
+    // though it's throwing exceptions (which would normally make us back off
+    // of ion compilation).
+    for (var i=0; i<1500; i++) {}
+    return threw;
+  }
+
+  var threw = false;
+  var el = document.createElement("div");
+  for (var i=0; i<200; i++)
+      threw = test(el);
+  assert_true(threw);
+}, "Shouldn't optimize away throwing functions");
+</script>
--- a/dom/network/tests/test_network_basics.html
+++ b/dom/network/tests/test_network_basics.html
@@ -8,29 +8,26 @@
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Network API **/
-
 function checkInterface(aInterface) {
-  ok(!(aInterface in window), aInterface + " should be prefixed");
-  ok(("Moz" + aInterface) in window, aInterface + " should be prefixed");
+  ok(!(aInterface in window), aInterface + " should not exist");
+  ok(!(("Moz" + aInterface) in window), aInterface + " should not exist");
 }
 
 function test() {
   ok('mozConnection' in navigator, "navigator.mozConnection should exist");
 
   ok(navigator.mozConnection, "navigator.mozConnection returns an object");
 
-  ok(navigator.mozConnection instanceof MozConnection,
-     "navigator.mozConnection is a MozConnection object");
   ok(navigator.mozConnection instanceof EventTarget,
      "navigator.mozConnection is a EventTarget object");
 
   checkInterface("Connection");
 
   ok('bandwidth' in navigator.mozConnection,
      "bandwidth should be a Connection attribute");
   is(navigator.mozConnection.bandwidth, Infinity,
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -606,18 +606,16 @@ var interfaceNamesInGlobalScope =
     {name: "MozActivity", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MozApplicationEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozCellBroadcast", b2g: true, pref: "dom.cellbroadcast.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozCellBroadcastEvent", b2g: true, pref: "dom.cellbroadcast.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "MozConnection", pref: "dom.network.enabled"},
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "mozContact",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MozContactChangeEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MozCSSKeyframeRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MozCSSKeyframesRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -40,17 +40,17 @@ interface Document : Node {
   readonly attribute DOMString contentType;
 
   [Pure]
   readonly attribute DocumentType? doctype;
   [Pure]
   readonly attribute Element? documentElement;
   [Pure]
   HTMLCollection getElementsByTagName(DOMString localName);
-  [Pure]
+  [Pure, Throws]
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   [Pure]
   HTMLCollection getElementsByClassName(DOMString classNames);
   [Pure]
   Element? getElementById(DOMString elementId);
 
   [NewObject, Throws]
   Element createElement(DOMString localName);
--- a/dom/webidl/MozConnection.webidl
+++ b/dom/webidl/MozConnection.webidl
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-[Pref="dom.network.enabled"]
+[Pref="dom.network.enabled", NoInterfaceObject]
 interface MozConnection : EventTarget {
   readonly attribute unrestricted double bandwidth;
   readonly attribute boolean metered;
 
   attribute EventHandler onchange;
 };
 
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -609,19 +609,17 @@ URL::SetHref(const nsAString& aHref, Err
   nsRefPtr<SetterRunnable> runnable =
     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHref, aHref,
                        mURLProxy, aRv);
 
   if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
     JS_ReportPendingException(mWorkerPrivate->GetJSContext());
   }
 
-  if (mSearchParams) {
-    mSearchParams->Invalidate();
-  }
+  UpdateURLSearchParams();
 }
 
 void
 URL::GetOrigin(nsString& aOrigin) const
 {
   nsRefPtr<GetterRunnable> runnable =
     new GetterRunnable(mWorkerPrivate, GetterRunnable::GetterOrigin, aOrigin,
                        mURLProxy);
@@ -817,20 +815,17 @@ URL::GetSearch(nsString& aSearch) const
     JS_ReportPendingException(mWorkerPrivate->GetJSContext());
   }
 }
 
 void
 URL::SetSearch(const nsAString& aSearch)
 {
   SetSearchInternal(aSearch);
-
-  if (mSearchParams) {
-    mSearchParams->Invalidate();
-  }
+  UpdateURLSearchParams();
 }
 
 void
 URL::SetSearchInternal(const nsAString& aSearch)
 {
   ErrorResult rv;
   nsRefPtr<SetterRunnable> runnable =
     new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterSearch,
@@ -850,26 +845,22 @@ URL::GetSearchParams()
 
 void
 URL::SetSearchParams(URLSearchParams* aSearchParams)
 {
   if (!aSearchParams) {
     return;
   }
 
-  if (!aSearchParams->HasURLAssociated()) {
-    MOZ_ASSERT(aSearchParams->IsValid());
-
-    mSearchParams = aSearchParams;
-    mSearchParams->SetObserver(this);
-  } else {
-    CreateSearchParamsIfNeeded();
-    mSearchParams->CopyFromURLSearchParams(*aSearchParams);
+  if (mSearchParams) {
+    mSearchParams->RemoveObserver(this);
   }
 
+  mSearchParams = aSearchParams;
+  mSearchParams->AddObserver(this);
 
   nsString search;
   mSearchParams->Serialize(search);
   SetSearchInternal(search);
 }
 
 void
 URL::GetHash(nsString& aHash) const
@@ -945,36 +936,36 @@ URL::RevokeObjectURL(const GlobalObject&
   if (!runnable->Dispatch(cx)) {
     JS_ReportPendingException(cx);
   }
 }
 
 void
 URL::URLSearchParamsUpdated()
 {
-  MOZ_ASSERT(mSearchParams && mSearchParams->IsValid());
+  MOZ_ASSERT(mSearchParams);
 
   nsString search;
   mSearchParams->Serialize(search);
   SetSearchInternal(search);
 }
 
 void
-URL::URLSearchParamsNeedsUpdates()
+URL::UpdateURLSearchParams()
 {
-  MOZ_ASSERT(mSearchParams);
-
-  nsString search;
-  GetSearch(search);
-  mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)));
+  if (mSearchParams) {
+    nsString search;
+    GetSearch(search);
+    mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)), this);
+  }
 }
 
 void
 URL::CreateSearchParamsIfNeeded()
 {
   if (!mSearchParams) {
     mSearchParams = new URLSearchParams();
-    mSearchParams->SetObserver(this);
-    mSearchParams->Invalidate();
+    mSearchParams->AddObserver(this);
+    UpdateURLSearchParams();
   }
 }
 
 END_WORKERS_NAMESPACE
--- a/dom/workers/URL.h
+++ b/dom/workers/URL.h
@@ -114,28 +114,29 @@ public:
 
   void Stringify(nsString& aRetval) const
   {
     GetHref(aRetval);
   }
 
   // IURLSearchParamsObserver
   void URLSearchParamsUpdated() MOZ_OVERRIDE;
-  void URLSearchParamsNeedsUpdates() MOZ_OVERRIDE;
 
 private:
   URLProxy* GetURLProxy() const
   {
     return mURLProxy;
   }
 
   void CreateSearchParamsIfNeeded();
 
   void SetSearchInternal(const nsAString& aSearch);
 
+  void UpdateURLSearchParams();
+
   WorkerPrivate* mWorkerPrivate;
   nsRefPtr<URLProxy> mURLProxy;
   nsRefPtr<URLSearchParams> mSearchParams;
 };
 
 END_WORKERS_NAMESPACE
 
 #endif /* mozilla_dom_workers_url_h__ */
--- a/dom/workers/test/urlSearchParams_worker.js
+++ b/dom/workers/test/urlSearchParams_worker.js
@@ -3,21 +3,16 @@ function ok(a, msg) {
   postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
 }
 
 function is(a, b, msg) {
   dump("IS: " + (a===b) + "  =>  " + a + " | " + b + " " + msg + "\n");
   postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
 }
 
-function isnot(a, b, msg) {
-  dump("ISNOT: " + (a!==b) + "  =>  " + a + " | " + b + " " + msg + "\n");
-  postMessage({type: 'status', status: a !== b, msg: a + " !== " + b + ": " + msg });
-}
-
 onmessage = function() {
   status = false;
   try {
     if ((URLSearchParams instanceof Object)) {
       status = true;
     }
   } catch(e) {
   }
@@ -129,17 +124,17 @@ onmessage = function() {
     is(url.href, 'http://www.example.net/?foo=bar', 'URL right');
 
     url.searchParams = null;
     is(url.searchParams.get('foo'), 'bar', "URL.searchParams.get('foo')");
     is(url.href, 'http://www.example.net/?foo=bar', 'URL right');
 
     var url2 = new URL('http://www.example.net?e=f');
     url.searchParams = url2.searchParams;
-    isnot(url.searchParams, url2.searchParams, "URL.searchParams is not the same object");
+    is(url.searchParams, url2.searchParams, "URL.searchParams is not the same object");
     is(url.searchParams.get('e'), 'f', "URL.searchParams.get('e')");
 
     url.href = "http://www.example.net?bar=foo";
     is(url.searchParams.get('bar'), 'foo', "URL.searchParams.get('bar')");
 
     runTest();
   }
 
@@ -159,22 +154,49 @@ onmessage = function() {
 
       var url2 = new URL(url.href);
       is(url2.searchParams.get('a'), encoding[i][0], 'a is still there');
     }
 
     runTest();
   }
 
+  function testMultiURL() {
+    var a = new URL('http://www.example.net?a=b&c=d');
+    var b = new URL('http://www.example.net?e=f');
+    ok(a.searchParams.has('a'), "a.searchParams.has('a')");
+    ok(a.searchParams.has('c'), "a.searchParams.has('c')");
+    ok(b.searchParams.has('e'), "b.searchParams.has('e')");
+
+    var u = new URLSearchParams();
+    a.searchParams = b.searchParams = u;
+    is(a.searchParams, u, "a.searchParams === u");
+    is(b.searchParams, u, "b.searchParams === u");
+    ok(!a.searchParams.has('a'), "!a.searchParams.has('a')");
+    ok(!a.searchParams.has('c'), "!a.searchParams.has('c')");
+    ok(!b.searchParams.has('e'), "!b.searchParams.has('e')");
+
+    u.append('foo', 'bar');
+    is(a.searchParams.get('foo'), 'bar', "a has foo=bar");
+    is(b.searchParams.get('foo'), 'bar', "b has foo=bar");
+    is(a + "", b + "", "stringify a == b");
+
+    a.search = "?bar=foo";
+    is(a.searchParams.get('bar'), 'foo', "a has bar=foo");
+    is(b.searchParams.get('bar'), 'foo', "b has bar=foo");
+
+    runTest();
+  }
   var tests = [
     testSimpleURLSearchParams,
     testCopyURLSearchParams,
     testParserURLSearchParams,
     testURL,
-    testEncoding
+    testEncoding,
+    testMultiURL
   ];
 
   function runTest() {
     if (!tests.length) {
       postMessage({type: 'finish' });
       return;
     }
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -667,20 +667,17 @@ MCall::New(TempAllocator &alloc, JSFunct
     if (!ins->init(alloc, maxArgc + NumNonArgumentOperands))
         return nullptr;
     return ins;
 }
 
 AliasSet
 MCallDOMNative::getAliasSet() const
 {
-    JS_ASSERT(getSingleTarget() && getSingleTarget()->isNative());
-
-    const JSJitInfo *jitInfo = getSingleTarget()->jitInfo();
-    JS_ASSERT(jitInfo);
+    const JSJitInfo *jitInfo = getJitInfo();
 
     JS_ASSERT(jitInfo->aliasSet() != JSJitInfo::AliasNone);
     // If we don't know anything about the types of our arguments, we have to
     // assume that type-coercions can have side-effects, so we need to alias
     // everything.
     if (jitInfo->aliasSet() != JSJitInfo::AliasDOMSets || !jitInfo->isTypedMethodJitInfo())
         return AliasSet::Store(AliasSet::Any);
 
@@ -718,20 +715,17 @@ MCallDOMNative::getAliasSet() const
 }
 
 void
 MCallDOMNative::computeMovable()
 {
     // We are movable if the jitinfo says we can be and if we're also not
     // effectful.  The jitinfo can't check for the latter, since it depends on
     // the types of our arguments.
-    JS_ASSERT(getSingleTarget() && getSingleTarget()->isNative());
-
-    const JSJitInfo *jitInfo = getSingleTarget()->jitInfo();
-    JS_ASSERT(jitInfo);
+    const JSJitInfo *jitInfo = getJitInfo();
 
     JS_ASSERT_IF(jitInfo->isMovable,
                  jitInfo->aliasSet() != JSJitInfo::AliasEverything);
 
     if (jitInfo->isMovable && !isEffectful())
         setMovable();
 }
 
@@ -765,16 +759,27 @@ MCallDOMNative::congruentTo(MDefinition 
         return false;
 
     // The other call had better be movable at this point!
     JS_ASSERT(call->isMovable());
 
     return true;
 }
 
+const JSJitInfo *
+MCallDOMNative::getJitInfo() const
+{
+    JS_ASSERT(getSingleTarget() && getSingleTarget()->isNative());
+
+    const JSJitInfo *jitInfo = getSingleTarget()->jitInfo();
+    JS_ASSERT(jitInfo);
+
+    return jitInfo;
+}
+
 MApplyArgs *
 MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDefinition *argc,
                 MDefinition *self)
 {
     return new(alloc) MApplyArgs(target, fun, argc, self);
 }
 
 MDefinition*
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1949,21 +1949,30 @@ class MCallDOMNative : public MCall
     // A helper class for MCalls for DOM natives.  Note that this is NOT
     // actually a separate MIR op from MCall, because all sorts of places use
     // isCall() to check for calls and all we really want is to overload a few
     // virtual things from MCall.
   protected:
     MCallDOMNative(JSFunction *target, uint32_t numActualArgs)
         : MCall(target, numActualArgs, false)
     {
+        // If our jitinfo is not marked movable, that means that our C++
+        // implementation is fallible or that we have no hope of ever doing the
+        // sort of argument analysis that would allow us to detemine that we're
+        // side-effect-free.  In the latter case we wouldn't get DCEd no matter
+        // what, but for the former case we have to explicitly say that we can't
+        // be DCEd.
+        if (!getJitInfo()->isMovable)
+            setGuard();
     }
 
     friend MCall *MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc,
                              size_t numActualArgs, bool construct, bool isDOMCall);
 
+    const JSJitInfo *getJitInfo() const;
   public:
     virtual AliasSet getAliasSet() const MOZ_OVERRIDE;
 
     virtual bool congruentTo(MDefinition *ins) const MOZ_OVERRIDE;
 
     virtual bool isCallDOMNative() const MOZ_OVERRIDE {
         return true;
     }
@@ -8027,16 +8036,21 @@ class MGetDOMProperty
 
         // Pin the guard as an operand if we want to hoist later
         setOperand(1, guard);
 
         // We are movable iff the jitinfo says we can be.
         if (isDomMovable()) {
             JS_ASSERT(jitinfo->aliasSet() != JSJitInfo::AliasEverything);
             setMovable();
+        } else {
+            // If we're not movable, that means we shouldn't be DCEd either,
+            // because we might throw an exception when called, and getting rid
+            // of that is observable.
+            setGuard();
         }
 
         setResultType(MIRType_Value);
     }
 
     const JSJitInfo *info() const {
         return info_;
     }
--- a/layout/reftests/flexbox/reftest.list
+++ b/layout/reftests/flexbox/reftest.list
@@ -62,21 +62,21 @@ fuzzy-if(B2G,10,3) random-if(winWidget) 
 == flexbox-dyn-changeFrameWidth-4.xhtml flexbox-dyn-changeFrameWidth-4-ref.xhtml
 == flexbox-dyn-changePadding-1a.xhtml flexbox-dyn-changePadding-1-ref.xhtml
 == flexbox-dyn-changePadding-1b.xhtml flexbox-dyn-changePadding-1-ref.xhtml
 
 # Tests for dynamic insertions of content into a flex container
 # (with existing [div | span | text] inside the flexbox, and new content
 # inserted adjacent to that existing content.)
 == flexbox-dyn-insertAroundDiv-1.xhtml flexbox-dyn-insertAroundDiv-1-ref.xhtml
-fuzzy-if(d2d&&layersGPUAccelerated,24,14) == flexbox-dyn-insertAroundDiv-2.xhtml flexbox-dyn-insertAroundDiv-2-ref.xhtml # bug 849692
+== flexbox-dyn-insertAroundDiv-2.xhtml flexbox-dyn-insertAroundDiv-2-ref.xhtml
 == flexbox-dyn-insertAroundDiv-3.xhtml flexbox-dyn-insertAroundDiv-3-ref.xhtml
 
 == flexbox-dyn-insertAroundSpan-1.xhtml flexbox-dyn-insertAroundDiv-1-ref.xhtml
-fuzzy-if(d2d&&layersGPUAccelerated,24,14) == flexbox-dyn-insertAroundSpan-2.xhtml flexbox-dyn-insertAroundDiv-2-ref.xhtml # bug 849692
+== flexbox-dyn-insertAroundSpan-2.xhtml flexbox-dyn-insertAroundDiv-2-ref.xhtml
 == flexbox-dyn-insertAroundSpan-3.xhtml flexbox-dyn-insertAroundDiv-3-ref.xhtml
 
 == flexbox-dyn-insertAroundText-1.xhtml flexbox-dyn-insertAroundText-1-ref.xhtml
 == flexbox-dyn-insertAroundText-2.xhtml flexbox-dyn-insertAroundText-2-ref.xhtml
 == flexbox-dyn-insertAroundText-3.xhtml flexbox-dyn-insertAroundText-3-ref.xhtml
 
 # Variant of one of the above tests, to regression-test an invalidation issue
 == flexbox-dyn-insertEmptySpan-1.xhtml flexbox-dyn-insertEmptySpan-1-ref.xhtml
--- a/mobile/android/base/GeckoAccessibility.java
+++ b/mobile/android/base/GeckoAccessibility.java
@@ -296,17 +296,17 @@ public class GeckoAccessibility {
                                 onInitializeAccessibilityNodeInfo(host, info);
                                 info.addChild(host, VIRTUAL_CURSOR_PREVIOUS);
                                 info.addChild(host, VIRTUAL_CURSOR_POSITION);
                                 info.addChild(host, VIRTUAL_CURSOR_NEXT);
                                 break;
                             default:
                                 info.setParent(host);
                                 info.setSource(host, virtualDescendantId);
-                                info.setVisibleToUser(host.isFocused());
+                                info.setVisibleToUser(host.isShown());
                                 info.setPackageName(GeckoAppShell.getContext().getPackageName());
                                 info.setClassName(host.getClass().getName());
                                 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
                                 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
                                 info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
                                 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
                                 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
                                 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -2639,17 +2639,17 @@ PlacesEditBookmarkURITransaction.prototy
     this.item.uri = PlacesUtils.bookmarks.getBookmarkURI(this.item.id);
     PlacesUtils.bookmarks.changeBookmarkURI(this.item.id, this.new.uri);
     // move tags from old URI to new URI
     this.item.tags = PlacesUtils.tagging.getTagsForURI(this.item.uri);
     if (this.item.tags.length != 0) {
       // only untag the old URI if this is the only bookmark
       if (PlacesUtils.getBookmarksForURI(this.item.uri, {}).length == 0)
         PlacesUtils.tagging.untagURI(this.item.uri, this.item.tags);
-      PlacesUtils.tagging.tagURI(this.new.URI, this.item.tags);
+      PlacesUtils.tagging.tagURI(this.new.uri, this.item.tags);
     }
   },
 
   undoTransaction: function EBUTXN_undoTransaction()
   {
     PlacesUtils.bookmarks.changeBookmarkURI(this.item.id, this.item.uri);
     // move tags from new URI to old URI 
     if (this.item.tags.length != 0) {
--- a/toolkit/components/places/tests/cpp/mock_Link.h
+++ b/toolkit/components/places/tests/cpp/mock_Link.h
@@ -118,19 +118,19 @@ Link::SizeOfExcludingThis(mozilla::Mallo
 
 void
 Link::URLSearchParamsUpdated()
 {
   NS_NOTREACHED("Unexpected call to Link::URLSearchParamsUpdated");
 }
 
 void
-Link::URLSearchParamsNeedsUpdates()
+Link::UpdateURLSearchParams()
 {
-  NS_NOTREACHED("Unexpected call to Link::URLSearchParamsNeedsUpdates");
+  NS_NOTREACHED("Unexpected call to Link::UpdateURLSearchParams");
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(URLSearchParams)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URLSearchParams)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(URLSearchParams)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(URLSearchParams)
@@ -154,29 +154,30 @@ URLSearchParams::~URLSearchParams()
 
 JSObject*
 URLSearchParams::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return nullptr;
 }
 
 void
-URLSearchParams::ParseInput(const nsACString& aInput)
+URLSearchParams::ParseInput(const nsACString& aInput,
+                            URLSearchParamsObserver* aObserver)
 {
   NS_NOTREACHED("Unexpected call to URLSearchParams::ParseInput");
 }
 
 void
-URLSearchParams::CopyFromURLSearchParams(URLSearchParams& aSearchParams)
+URLSearchParams::AddObserver(URLSearchParamsObserver* aObserver)
 {
-  NS_NOTREACHED("Unexpected call to URLSearchParams::CopyFromURLSearchParams");
+  NS_NOTREACHED("Unexpected call to URLSearchParams::SetObserver");
 }
 
 void
-URLSearchParams::SetObserver(URLSearchParamsObserver* aObserver)
+URLSearchParams::RemoveObserver(URLSearchParamsObserver* aObserver)
 {
   NS_NOTREACHED("Unexpected call to URLSearchParams::SetObserver");
 }
 
 void
 URLSearchParams::Serialize(nsAString& aValue) const
 {
   NS_NOTREACHED("Unexpected call to URLSearchParams::Serialize");
@@ -227,24 +228,17 @@ URLSearchParams::Delete(const nsAString&
 
 void
 URLSearchParams::DeleteAll()
 {
   NS_NOTREACHED("Unexpected call to URLSearchParams::DeleteAll");
 }
 
 void
-URLSearchParams::NotifyObserver()
+URLSearchParams::NotifyObservers(URLSearchParamsObserver* aExceptObserver)
 {
-  NS_NOTREACHED("Unexpected call to URLSearchParams::NotifyObserver");
+  NS_NOTREACHED("Unexpected call to URLSearchParams::NotifyObservers");
 }
 
-void
-URLSearchParams::Invalidate()
-{
-  NS_NOTREACHED("Unexpected call to URLSearchParams::Invalidate");
-}
-
-
 } // namespace dom
 } // namespace mozilla
 
 #endif // mock_Link_h__
--- a/toolkit/components/places/tests/unit/test_419731.js
+++ b/toolkit/components/places/tests/unit/test_419731.js
@@ -1,115 +1,96 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
-// Get history services
-try {
-  var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
-                getService(Ci.nsINavHistoryService);
-  var bhist = histsvc.QueryInterface(Ci.nsIBrowserHistory);
-} catch(ex) {
-  do_throw("Could not get history services\n");
-}
-
-// Get bookmark service
-try {
-  var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
-              getService(Ci.nsINavBookmarksService);
-}
-catch(ex) {
-  do_throw("Could not get the nav-bookmarks-service\n");
-}
-
-// Get tagging service
-try {
-  var tagssvc = Cc["@mozilla.org/browser/tagging-service;1"].
-                getService(Ci.nsITaggingService);
-} catch(ex) {
-  do_throw("Could not get tagging service\n");
-}
-
-
-// main
 function run_test() {
-  var uri1 = uri("http://foo.bar/");
+  let uri1 = NetUtil.newURI("http://foo.bar/");
 
   // create 2 bookmarks
-  var bookmark1id = bmsvc.insertBookmark(bmsvc.bookmarksMenuFolder, uri1,
-                                         bmsvc.DEFAULT_INDEX, "title 1");
-  var bookmark2id = bmsvc.insertBookmark(bmsvc.toolbarFolder, uri1,
-                                         bmsvc.DEFAULT_INDEX, "title 2");
+  let bookmark1id = PlacesUtils.bookmarks
+                               .insertBookmark(PlacesUtils.bookmarksMenuFolderId,
+                                               uri1,
+                                               PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                               "title 1");
+  let bookmark2id = PlacesUtils.bookmarks
+                               .insertBookmark(PlacesUtils.toolbarFolderId,
+                                               uri1,
+                                               PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                               "title 2");
   // add a new tag
-  tagssvc.tagURI(uri1, ["foo"]);
+  PlacesUtils.tagging.tagURI(uri1, ["foo"]);
 
   // get tag folder id
-  var options = histsvc.getNewQueryOptions();
-  var query = histsvc.getNewQuery();
-  query.setFolders([bmsvc.tagsFolder], 1);
-  var result = histsvc.executeQuery(query, options);
-  var tagRoot = result.root;
+  let options = PlacesUtils.history.getNewQueryOptions();
+  let query = PlacesUtils.history.getNewQuery();
+  query.setFolders([PlacesUtils.tagsFolderId], 1);
+  let result = PlacesUtils.history.executeQuery(query, options);
+  let tagRoot = result.root;
   tagRoot.containerOpen = true;
-  var tagNode = tagRoot.getChild(0)
+  let tagNode = tagRoot.getChild(0)
                        .QueryInterface(Ci.nsINavHistoryContainerResultNode);
-  var tagItemId = tagNode.itemId;
+  let tagItemId = tagNode.itemId;
   tagRoot.containerOpen = false;
 
   // change bookmark 1 title
-  bmsvc.setItemTitle(bookmark1id, "new title 1");
+  PlacesUtils.bookmarks.setItemTitle(bookmark1id, "new title 1");
+
+  // Workaround timers resolution and time skews.
+  let bookmark2LastMod = PlacesUtils.bookmarks.getItemLastModified(bookmark2id);
+  PlacesUtils.bookmarks.setItemLastModified(bookmark1id, bookmark2LastMod + 1);
 
   // Query the tag.
-  options = histsvc.getNewQueryOptions();
+  options = PlacesUtils.history.getNewQueryOptions();
   options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
   options.resultType = options.RESULTS_AS_TAG_QUERY;
 
-  query = histsvc.getNewQuery();
-  result = histsvc.executeQuery(query, options);
-  var root = result.root;
+  query = PlacesUtils.history.getNewQuery();
+  result = PlacesUtils.history.executeQuery(query, options);
+  let root = result.root;
   root.containerOpen = true;
   do_check_eq(root.childCount, 1);
 
-  var theTag = root.getChild(0)
+  let theTag = root.getChild(0)
                    .QueryInterface(Ci.nsINavHistoryContainerResultNode);
   // Bug 524219: Check that renaming the tag shows up in the result.
   do_check_eq(theTag.title, "foo")
-  bmsvc.setItemTitle(tagItemId, "bar");
+  PlacesUtils.bookmarks.setItemTitle(tagItemId, "bar");
 
   // Check that the item has been replaced
   do_check_neq(theTag, root.getChild(0));
-  var theTag = root.getChild(0)
+  theTag = root.getChild(0)
                    .QueryInterface(Ci.nsINavHistoryContainerResultNode);
   do_check_eq(theTag.title, "bar");
 
   // Check that tag container contains new title
   theTag.containerOpen = true;
   do_check_eq(theTag.childCount, 1);
-  var node = theTag.getChild(0);
+  let node = theTag.getChild(0);
   do_check_eq(node.title, "new title 1");
   theTag.containerOpen = false;
   root.containerOpen = false;
 
   // Change bookmark 2 title.
-  bmsvc.setItemTitle(bookmark2id, "new title 2");
+  PlacesUtils.bookmarks.setItemTitle(bookmark2id, "new title 2");
 
-  // Workaround VM timers issues.
-  var bookmark1LastMod = bmsvc.getItemLastModified(bookmark1id);
-  bmsvc.setItemLastModified(bookmark2id, bookmark1LastMod + 1);
+  // Workaround timers resolution and time skews.
+  let bookmark1LastMod = PlacesUtils.bookmarks.getItemLastModified(bookmark1id);
+  PlacesUtils.bookmarks.setItemLastModified(bookmark2id, bookmark1LastMod + 1);
 
   // Check that tag container contains new title
-  options = histsvc.getNewQueryOptions();
+  options = PlacesUtils.history.getNewQueryOptions();
   options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
   options.resultType = options.RESULTS_AS_TAG_CONTENTS;
 
-  query = histsvc.getNewQuery();
+  query = PlacesUtils.history.getNewQuery();
   query.setFolders([tagItemId], 1);
-  result = histsvc.executeQuery(query, options);
+  result = PlacesUtils.history.executeQuery(query, options);
   root = result.root;
 
   root.containerOpen = true;
-  var cc = root.childCount;
-  do_check_eq(cc, 1);
+  do_check_eq(root.childCount, 1);
   node = root.getChild(0);
   do_check_eq(node.title, "new title 2");
   root.containerOpen = false;
 }
--- a/toolkit/components/places/tests/unit/test_placesTxn.js
+++ b/toolkit/components/places/tests/unit/test_placesTxn.js
@@ -40,16 +40,20 @@ let observer = {
     this._itemRemovedIndex = index;
   },
   _itemRemovedId: null,
   _itemRemovedFolder: null,
   _itemRemovedIndex: null,
 
   onItemChanged: function(id, property, isAnnotationProperty, newValue,
                           lastModified, itemType) {
+    // The transaction manager is being rewritten in bug 891303, so just
+    // skip checking this for now.
+    if (property == "tags")
+      return;
     this._itemChangedId = id;
     this._itemChangedProperty = property;
     this._itemChanged_isAnnotationProperty = isAnnotationProperty;
     this._itemChangedValue = newValue;
   },
   _itemChangedId: null,
   _itemChangedProperty: null,
   _itemChanged_isAnnotationProperty: null,
@@ -468,41 +472,51 @@ add_test(function test_editing_item_titl
   do_check_eq(observer._itemChangedId, testBkmId);
   do_check_eq(observer._itemChangedProperty, "title");
   do_check_eq(observer._itemChangedValue, TITLE);
 
   run_next_test();
 });
 
 add_test(function test_editing_item_uri() {
-  const OLD_TEST_URL = "http://old.test_editing_item_uri.com/";
-  const NEW_TEST_URL = "http://new.test_editing_item_uri.com/";
-  let testBkmId = bmsvc.insertBookmark(root, NetUtil.newURI(OLD_TEST_URL), bmsvc.DEFAULT_INDEX, "Test editing item title");
+  const OLD_TEST_URI = NetUtil.newURI("http://old.test_editing_item_uri.com/");
+  const NEW_TEST_URI = NetUtil.newURI("http://new.test_editing_item_uri.com/");
+  let testBkmId = bmsvc.insertBookmark(root, OLD_TEST_URI, bmsvc.DEFAULT_INDEX,
+                                       "Test editing item title");
+  tagssvc.tagURI(OLD_TEST_URI, ["tag"]);
 
-  let txn = new PlacesEditBookmarkURITransaction(testBkmId, NetUtil.newURI(NEW_TEST_URL));
+  let txn = new PlacesEditBookmarkURITransaction(testBkmId, NEW_TEST_URI);
 
   txn.doTransaction();
   do_check_eq(observer._itemChangedId, testBkmId);
   do_check_eq(observer._itemChangedProperty, "uri");
-  do_check_eq(observer._itemChangedValue, NEW_TEST_URL);
+  do_check_eq(observer._itemChangedValue, NEW_TEST_URI.spec);
+  do_check_eq(JSON.stringify(tagssvc.getTagsForURI(NEW_TEST_URI)), JSON.stringify(["tag"]));
+  do_check_eq(JSON.stringify(tagssvc.getTagsForURI(OLD_TEST_URI)), JSON.stringify([]));
 
   txn.undoTransaction();
   do_check_eq(observer._itemChangedId, testBkmId);
   do_check_eq(observer._itemChangedProperty, "uri");
-  do_check_eq(observer._itemChangedValue, OLD_TEST_URL);
+  do_check_eq(observer._itemChangedValue, OLD_TEST_URI.spec);
+  do_check_eq(JSON.stringify(tagssvc.getTagsForURI(OLD_TEST_URI)), JSON.stringify(["tag"]));
+  do_check_eq(JSON.stringify(tagssvc.getTagsForURI(NEW_TEST_URI)), JSON.stringify([]));
 
   txn.redoTransaction();
   do_check_eq(observer._itemChangedId, testBkmId);
   do_check_eq(observer._itemChangedProperty, "uri");
-  do_check_eq(observer._itemChangedValue, NEW_TEST_URL);
+  do_check_eq(observer._itemChangedValue, NEW_TEST_URI.spec);
+  do_check_eq(JSON.stringify(tagssvc.getTagsForURI(NEW_TEST_URI)), JSON.stringify(["tag"]));
+  do_check_eq(JSON.stringify(tagssvc.getTagsForURI(OLD_TEST_URI)), JSON.stringify([]));
 
   txn.undoTransaction();
   do_check_eq(observer._itemChangedId, testBkmId);
   do_check_eq(observer._itemChangedProperty, "uri");
-  do_check_eq(observer._itemChangedValue, OLD_TEST_URL);
+  do_check_eq(observer._itemChangedValue, OLD_TEST_URI.spec);
+  do_check_eq(JSON.stringify(tagssvc.getTagsForURI(OLD_TEST_URI)), JSON.stringify(["tag"]));
+  do_check_eq(JSON.stringify(tagssvc.getTagsForURI(NEW_TEST_URI)), JSON.stringify([]));
 
   run_next_test();
 });
 
 add_test(function test_edit_description_transaction() {
   let testURI = NetUtil.newURI("http://test_edit_description_transaction.com");
   let testBkmId = bmsvc.insertBookmark(root, testURI, bmsvc.DEFAULT_INDEX, "Test edit description transaction");
 
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -97,16 +97,17 @@ typedef struct _nsCocoaWindowList {
 
 - (void)mouseEntered:(NSEvent*)aEvent;
 - (void)mouseExited:(NSEvent*)aEvent;
 - (void)mouseMoved:(NSEvent*)aEvent;
 - (void)updateTrackingArea;
 - (NSView*)trackingAreaView;
 
 - (void)setBeingShown:(BOOL)aValue;
+- (BOOL)isBeingShown;
 - (BOOL)isVisibleOrBeingShown;
 
 - (ChildView*)mainChildView;
 
 - (NSArray*)titlebarControls;
 
 - (void)setWantsTitleDrawn:(BOOL)aDrawTitle;
 - (BOOL)wantsTitleDrawn;
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -585,17 +585,17 @@ void* nsCocoaWindow::GetNativeData(uint3
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
 }
 
 bool nsCocoaWindow::IsVisible() const
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
-  return (mWindow && ([mWindow isVisible] || mSheetNeedsShow));
+  return (mWindow && ([mWindow isVisibleOrBeingShown] || mSheetNeedsShow));
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
 }
 
 NS_IMETHODIMP nsCocoaWindow::SetModal(bool aState)
 {
   if (!mWindow)
     return NS_OK;
@@ -681,24 +681,33 @@ NS_IMETHODIMP nsCocoaWindow::Show(bool b
   if (!mWindow)
     return NS_OK;
 
   // We need to re-execute sometimes in order to bring already-visible
   // windows forward.
   if (!mSheetNeedsShow && !bState && ![mWindow isVisible])
     return NS_OK;
 
+  // Protect against re-entering.
+  if (bState && [mWindow isBeingShown])
+    return NS_OK;
+
   [mWindow setBeingShown:bState];
 
   nsIWidget* parentWidget = mParent;
   nsCOMPtr<nsPIWidgetCocoa> piParentWidget(do_QueryInterface(parentWidget));
   NSWindow* nativeParentWindow = (parentWidget) ?
     (NSWindow*)parentWidget->GetNativeData(NS_NATIVE_WINDOW) : nil;
 
   if (bState && !mBounds.IsEmpty()) {
+    if (mPopupContentView) {
+      // Ensure our content view is visible. We never need to hide it.
+      mPopupContentView->Show(true);
+    }
+
     if (mWindowType == eWindowType_sheet) {
       // bail if no parent window (its basically what we do in Carbon)
       if (!nativeParentWindow || !piParentWidget)
         return NS_ERROR_FAILURE;
 
       NSWindow* topNonSheetWindow = nativeParentWindow;
       
       // If this sheet is the child of another sheet, hide the parent so that
@@ -751,16 +760,17 @@ NS_IMETHODIMP nsCocoaWindow::Show(bool b
       [mWindow _setWindowNumber:-1];
       [mWindow _setWindowNumber:windowNumber];
       // For reasons that aren't yet clear, calls to [NSWindow orderFront:] or
       // [NSWindow makeKeyAndOrderFront:] can sometimes trigger "Error (1000)
       // creating CGSWindow", which in turn triggers an internal inconsistency
       // NSException.  These errors shouldn't be fatal.  So we need to wrap
       // calls to ...orderFront: in LOGONLY blocks.  See bmo bug 470864.
       NS_OBJC_BEGIN_TRY_LOGONLY_BLOCK;
+      [[mWindow contentView] setNeedsDisplay:YES];
       [mWindow orderFront:nil];
       NS_OBJC_END_TRY_LOGONLY_BLOCK;
       SendSetZLevelEvent();
       AdjustWindowShadow();
       SetWindowBackgroundBlur();
       // If our popup window is a non-native context menu, tell the OS (and
       // other programs) that a menu has opened.  This is how the OS knows to
       // close other programs' context menus when ours open.
@@ -897,21 +907,16 @@ NS_IMETHODIMP nsCocoaWindow::Show(bool b
       if ([mWindow isKindOfClass:[PopupWindow class]] &&
           [(PopupWindow*) mWindow isContextMenu]) {
         [[NSDistributedNotificationCenter defaultCenter]
           postNotificationName:@"com.apple.HIToolbox.endMenuTrackingNotification"
                         object:@"org.mozilla.gecko.PopupWindow"];
       }
     }
   }
-  
-  if (mPopupContentView) {
-    mPopupContentView->Show(bState);
-    [[mWindow contentView] setNeedsDisplay:YES];
-  }
 
   [mWindow setBeingShown:NO];
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
@@ -2632,16 +2637,21 @@ static NSMutableSet *gSwizzledFrameViewC
   return self;
 }
 
 - (void)setBeingShown:(BOOL)aValue
 {
   mBeingShown = aValue;
 }
 
+- (BOOL)isBeingShown
+{
+  return mBeingShown;
+}
+
 - (BOOL)isVisibleOrBeingShown
 {
   return [super isVisible] || mBeingShown;
 }
 
 - (void)disableSetNeedsDisplay
 {
   mDisabledNeedsDisplay = YES;