Merge m-c to m-i
authorMs2ger <ms2ger@gmail.com>
Sat, 13 Aug 2011 14:47:03 +0200
changeset 74367 19ab9ba1c62369998649c5c0192aeafc0b74a230
parent 74366 8e1dd6f8b903ccbb4fcdff817b606fda45d41311 (current diff)
parent 74340 d7ccb99a2f2d04e406e9f91ff0ecd7dd811a5ed2 (diff)
child 74368 53bbf9d8a0e5833a72eb87c5981a11bb35fa85fb
push id1193
push userMs2ger@gmail.com
push dateSat, 13 Aug 2011 12:50:08 +0000
treeherdermozilla-inbound@19ab9ba1c623 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone8.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to m-i
browser/base/content/test/test_contextmenu.html
editor/libeditor/html/tests/test_bug484181.html
gfx/thebes/gfxFont.cpp
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -583,16 +583,17 @@ function startTest() {
     img    = subwindow.document.getElementById("test-image");
     canvas = subwindow.document.getElementById("test-canvas");
     video_ok   = subwindow.document.getElementById("test-video-ok");
     video_bad  = subwindow.document.getElementById("test-video-bad");
     video_bad2 = subwindow.document.getElementById("test-video-bad2");
     iframe = subwindow.document.getElementById("test-iframe");
     textarea = subwindow.document.getElementById("test-textarea");
     contenteditable = subwindow.document.getElementById("test-contenteditable");
+    contenteditable.focus(); // content editable needs to be focused to enable spellcheck
     inputspell = subwindow.document.getElementById("test-input-spellcheck");
     pagemenu = subwindow.document.getElementById("test-pagemenu");
 
     contextMenu.addEventListener("popupshown", function() { runTest(++testNum); }, false);
     runTest(1);
 }
 
 // We open this in a separate window, because the Mochitests run inside a frame.
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -736,17 +736,16 @@ toolbar[mode="icons"] #forward-button:-m
 
 toolbar[mode="icons"] #zoom-out-button {
   -moz-margin-end: 0;
 }
 
 toolbar[mode="icons"] #zoom-in-button {
   -moz-border-start: none;
   -moz-margin-start: 0;
-  height: 16px;
 }
 
 #zoom-out-button:-moz-locale-dir(ltr),
 #zoom-in-button:-moz-locale-dir(rtl) {
   border-top-right-radius: 0;
   border-bottom-right-radius: 0;
 }
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1076,16 +1076,17 @@ else
 	$(QUANTIFY) $(CC) -o $^.quantify $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
 endif
 ifndef NO_DIST_INSTALL
 	$(INSTALL) $(IFLAGS2) $^.quantify $(FINAL_TARGET)
 endif
 
 ifdef DTRACE_PROBE_OBJ
 EXTRA_DEPS += $(DTRACE_PROBE_OBJ)
+OBJS += $(DTRACE_PROBE_OBJ)
 endif
 
 $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
 	$(RM) $(LIBRARY)
 	$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS)
 	$(RANLIB) $@
 
 $(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
@@ -1116,18 +1117,18 @@ endif # OS/2
 	$(RM) $@
 	$(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
 	$(HOST_RANLIB) $@
 
 ifdef HAVE_DTRACE
 ifndef XP_MACOSX
 ifdef DTRACE_PROBE_OBJ
 ifndef DTRACE_LIB_DEPENDENT
-$(DTRACE_PROBE_OBJ): $(OBJS)
-	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(OBJS)
+$(DTRACE_PROBE_OBJ):
+	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ)
 endif
 endif
 endif
 endif
 
 # On Darwin (Mac OS X), dwarf2 debugging uses debug info left in .o files,
 # so instead of deleting .o files after repacking them into a dylib, we make
 # symlinks back to the originals. The symlinks are a no-op for stabs debugging,
@@ -1139,17 +1140,17 @@ ifndef INCREMENTAL_LINKER
 endif
 ifdef DTRACE_LIB_DEPENDENT
 ifndef XP_MACOSX
 	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o  $(DTRACE_PROBE_OBJ) $(shell $(EXPAND_LIBS) $(MOZILLA_PROBE_LIBS))
 endif
 	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(LOBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(MOZILLA_PROBE_LIBS) $(RESFILE) $(LDFLAGS) $(SHARED_LIBRARY_LIBS) $(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) $(DEF_FILE) $(SHLIB_LDENDFILE)
 	@$(RM) $(DTRACE_PROBE_OBJ)
 else # ! DTRACE_LIB_DEPENDENT
-	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(DTRACE_PROBE_OBJ) $(LOBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(SHARED_LIBRARY_LIBS) $(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) $(DEF_FILE) $(SHLIB_LDENDFILE)
+	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(LOBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(SHARED_LIBRARY_LIBS) $(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) $(DEF_FILE) $(SHLIB_LDENDFILE)
 endif # DTRACE_LIB_DEPENDENT
 	@$(call CHECK_STDCXX,$@)
 
 ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
 ifdef MSMANIFEST_TOOL
 ifdef EMBED_MANIFEST_AT
 	@if test -f $@.manifest; then \
 		mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;$(EMBED_MANIFEST_AT); \
--- a/configure.in
+++ b/configure.in
@@ -7588,16 +7588,28 @@ dnl ====================================
 MOZ_ARG_ENABLE_BOOL(gczeal,
 [  --enable-gczeal         Enable zealous JavaScript GCing],
     JS_GC_ZEAL=1,
     JS_GC_ZEAL= )
 if test -n "$JS_GC_ZEAL"; then
     AC_DEFINE(JS_GC_ZEAL)
 fi
 
+dnl ========================================================
+dnl JS opt-mode assertions and minidump instrumentation
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(js-diagnostics,
+[  --enable-js-diagnostics
+                          Enable JS diagnostic assertions and breakpad data],
+    JS_CRASH_DIAGNOSTICS=1,
+    JS_CRASH_DIAGNOSTICS= )
+if test -n "$JS_CRASH_DIAGNOSTICS"; then
+    AC_DEFINE(JS_CRASH_DIAGNOSTICS)
+fi
+
 dnl ======================================================
 dnl = Enable compiling with ccache
 dnl ======================================================
 MOZ_ARG_WITH_STRING(ccache,
 [  --with-ccache[=path/to/ccache]
                           Enable compiling with ccache],
     CCACHE=$withval, CCACHE="no")
 
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -939,16 +939,41 @@ public:
 
   /**
    * If the content is a part of HTML editor, this returns editing
    * host content.  When the content is in designMode, this returns its body
    * element.  Also, when the content isn't editable, this returns null.
    */
   nsIContent* GetEditingHost();
 
+  /**
+   * Determing language. Look at the nearest ancestor element that has a lang
+   * attribute in the XML namespace or is an HTML element and has a lang in
+   * no namespace attribute.
+   */
+  void GetLang(nsAString& aResult) const {
+    for (const nsIContent* content = this; content; content = content->GetParent()) {
+      if (content->GetAttrCount() > 0) {
+        // xml:lang has precedence over lang on HTML elements (see
+        // XHTML1 section C.7).
+        PRBool hasAttr = content->GetAttr(kNameSpaceID_XML, nsGkAtoms::lang,
+                                          aResult);
+        if (!hasAttr && content->IsHTML()) {
+          hasAttr = content->GetAttr(kNameSpaceID_None, nsGkAtoms::lang,
+                                     aResult);
+        }
+        NS_ASSERTION(hasAttr || aResult.IsEmpty(),
+                     "GetAttr that returns false should not make string non-empty");
+        if (hasAttr) {
+          return;
+        }
+      }
+    }
+  }
+
   // Overloaded from nsINode
   virtual already_AddRefed<nsIURI> GetBaseURI() const;
 
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
 protected:
   /**
    * Hook for implementing GetID.  This is guaranteed to only be
--- a/editor/composer/src/nsEditorSpellCheck.cpp
+++ b/editor/composer/src/nsEditorSpellCheck.cpp
@@ -37,28 +37,33 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsEditorSpellCheck.h"
 
+#include "nsStyleUtil.h"
+#include "nsIContent.h"
+#include "nsIDOMElement.h"
 #include "nsITextServicesDocument.h"
 #include "nsISpellChecker.h"
 #include "nsISelection.h"
 #include "nsIDOMRange.h"
 #include "nsIEditor.h"
+#include "nsIHTMLEditor.h"
 
 #include "nsIComponentManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIChromeRegistry.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsITextServicesFilter.h"
+#include "nsUnicharUtils.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEditorSpellCheck)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEditorSpellCheck)
 
@@ -178,71 +183,19 @@ nsEditorSpellCheck::InitSpellChecker(nsI
   mSpellChecker = do_CreateInstance(NS_SPELLCHECKER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NULL_POINTER);
 
   rv = mSpellChecker->SetDocument(tsDoc, PR_TRUE);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Tell the spellchecker what dictionary to use:
-
-  nsAdoptingString dictName =
-    Preferences::GetLocalizedString("spellchecker.dictionary");
-
-  if (dictName.IsEmpty())
-  {
-    // Prefs didn't give us a dictionary name, so just get the current
-    // locale and use that as the default dictionary name!
-
-    nsCOMPtr<nsIXULChromeRegistry> packageRegistry =
-      mozilla::services::GetXULChromeRegistryService();
-
-    if (packageRegistry) {
-      nsCAutoString utf8DictName;
-      rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global"),
-                                              utf8DictName);
-      AppendUTF8toUTF16(utf8DictName, dictName);
-    }
-  }
-
-  PRBool setDictionary = PR_FALSE;
-  if (NS_SUCCEEDED(rv) && !dictName.IsEmpty()) {
-    rv = SetCurrentDictionary(dictName.get());
-
-    // fall back to "en-US" if the current locale doesn't have a dictionary.
-    if (NS_FAILED(rv)) {
-      rv = SetCurrentDictionary(NS_LITERAL_STRING("en-US").get());
-    }
-
-    if (NS_SUCCEEDED(rv))
-      setDictionary = PR_TRUE;
-  }
-
-  // If there was no dictionary specified by spellchecker.dictionary and setting it to the 
-  // locale dictionary didn't work, try to use the first dictionary we find. This helps when 
-  // the first dictionary is installed
-  if (! setDictionary) {
-    nsTArray<nsString> dictList;
-    rv = mSpellChecker->GetDictionaryList(&dictList);
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (dictList.Length() > 0) {
-      rv = SetCurrentDictionary(dictList[0].get());
-      if (NS_SUCCEEDED(rv))
-        SaveDefaultDictionary();
-    }
-  }
-
-  // If an error was thrown while checking the dictionary pref, just
-  // fail silently so that the spellchecker dialog is allowed to come
-  // up. The user can manually reset the language to their choice on
-  // the dialog if it is wrong.
-
-  DeleteSuggestedWordList();
-
+  // do not fail if UpdateCurrentDictionary fails because this method may
+  // succeed later.
+  UpdateCurrentDictionary(aEditor);
   return NS_OK;
 }
 
 NS_IMETHODIMP    
 nsEditorSpellCheck::GetNextMisspelledWord(PRUnichar **aNextMisspelledWord)
 {
   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
 
@@ -434,24 +387,16 @@ nsEditorSpellCheck::SetCurrentDictionary
   return mSpellChecker->SetCurrentDictionary(nsDependentString(aDictionary));
 }
 
 NS_IMETHODIMP    
 nsEditorSpellCheck::UninitSpellChecker()
 {
   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
 
-  // we preserve the last selected language, but ignore errors so we continue
-  // to uninitialize
-#ifdef DEBUG
-  nsresult rv =
-#endif
-  SaveDefaultDictionary();
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to set default dictionary");
-
   // Cleanup - kill the spell checker
   DeleteSuggestedWordList();
   mDictionaryList.Clear();
   mDictionaryIndex = 0;
   mSpellChecker = 0;
   return NS_OK;
 }
 
@@ -484,8 +429,129 @@ nsEditorSpellCheck::SetFilter(nsITextSer
 
 nsresult    
 nsEditorSpellCheck::DeleteSuggestedWordList()
 {
   mSuggestedWordList.Clear();
   mSuggestedWordIndex = 0;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditor* aEditor)
+{
+  nsresult rv;
+
+  // Tell the spellchecker what dictionary to use:
+  nsAutoString dictName;
+
+  // First, try to get language with html5 algorithm
+  nsAutoString editorLang;
+
+  nsCOMPtr<nsIContent> rootContent;
+
+  nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(aEditor);
+  if (htmlEditor) {
+    rootContent = htmlEditor->GetActiveEditingHost();
+  } else {
+    nsCOMPtr<nsIDOMElement> rootElement;
+    rv = aEditor->GetRootElement(getter_AddRefs(rootElement));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rootContent = do_QueryInterface(rootElement);
+  }
+  NS_ENSURE_TRUE(rootContent, NS_ERROR_FAILURE);
+
+  rootContent->GetLang(editorLang);
+
+  if (editorLang.IsEmpty()) {
+    nsCOMPtr<nsIDocument> doc = rootContent->GetCurrentDoc();
+    NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+    doc->GetContentLanguage(editorLang);
+  }
+
+  if (!editorLang.IsEmpty()) {
+    dictName.Assign(editorLang);
+  }
+
+  // otherwise, get language from preferences
+  if (dictName.IsEmpty()) {
+    dictName.Assign(Preferences::GetLocalizedString("spellchecker.dictionary"));
+  }
+
+  if (dictName.IsEmpty())
+  {
+    // Prefs didn't give us a dictionary name, so just get the current
+    // locale and use that as the default dictionary name!
+
+    nsCOMPtr<nsIXULChromeRegistry> packageRegistry =
+      mozilla::services::GetXULChromeRegistryService();
+
+    if (packageRegistry) {
+      nsCAutoString utf8DictName;
+      rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global"),
+                                              utf8DictName);
+      AppendUTF8toUTF16(utf8DictName, dictName);
+    }
+  }
+
+  SetCurrentDictionary(NS_LITERAL_STRING("").get());
+
+  if (NS_SUCCEEDED(rv) && !dictName.IsEmpty()) {
+    rv = SetCurrentDictionary(dictName.get());
+    if (NS_FAILED(rv)) {
+      // required dictionary was not available. Try to get a dictionary
+      // matching at least language part of dictName: If required dictionary is
+      // "aa-bb", we try "aa", then we try any available dictionary aa-XX
+      nsAutoString langCode;
+      PRInt32 dashIdx = dictName.FindChar('-');
+      if (dashIdx != -1) {
+        langCode.Assign(Substring(dictName, 0, dashIdx));
+        // try to use langCode
+        rv = SetCurrentDictionary(langCode.get());
+      } else {
+        langCode.Assign(dictName);
+      }
+      if (NS_FAILED(rv)) {
+        // loop over avaible dictionaries; if we find one with required
+        // language, use it
+        nsTArray<nsString> dictList;
+        rv = mSpellChecker->GetDictionaryList(&dictList);
+        NS_ENSURE_SUCCESS(rv, rv);
+        nsDefaultStringComparator comparator;
+        PRInt32 i, count = dictList.Length();
+        for (i = 0; i < count; i++) {
+          nsAutoString dictStr(dictList.ElementAt(i));
+          if (nsStyleUtil::DashMatchCompare(dictStr, langCode, comparator) &&
+              NS_SUCCEEDED(SetCurrentDictionary(dictStr.get()))) {
+              break;
+          }
+        }
+      }
+    }
+  }
+
+  // If we have not set dictionary, and the editable element doesn't have a
+  // lang attribute, we try to get a dictionary. First try, en-US. If it does
+  // not work, pick the first one.
+  if (editorLang.IsEmpty()) {
+    nsAutoString currentDictonary;
+    rv = mSpellChecker->GetCurrentDictionary(currentDictonary);
+    if (NS_FAILED(rv) || currentDictonary.IsEmpty()) {
+      rv = SetCurrentDictionary(NS_LITERAL_STRING("en-US").get());
+      if (NS_FAILED(rv)) {
+        nsTArray<nsString> dictList;
+        rv = mSpellChecker->GetDictionaryList(&dictList);
+        if (NS_SUCCEEDED(rv) && dictList.Length() > 0) {
+          SetCurrentDictionary(dictList[0].get());
+        }
+      }
+    }
+  }
+
+  // If an error was thrown while setting the dictionary, just
+  // fail silently so that the spellchecker dialog is allowed to come
+  // up. The user can manually reset the language to their choice on
+  // the dialog if it is wrong.
+
+  DeleteSuggestedWordList();
+
+  return NS_OK;
+}
--- a/editor/idl/nsIEditorSpellCheck.idl
+++ b/editor/idl/nsIEditorSpellCheck.idl
@@ -36,17 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
  
 #include "nsISupports.idl"
 
 interface nsIEditor;
 interface nsITextServicesFilter;
 
-[scriptable, uuid(90c93610-c116-44ab-9793-62dccb9f43ce)]
+[scriptable, uuid(803ff0dd-07f2-4438-b3a6-ab9c2fe4e1dd)]
 interface nsIEditorSpellCheck : nsISupports
 {
 
  /**
    * Returns true if we can enable spellchecking. If there are no available
    * dictionaries, this will return false.
    */
   boolean       canSpellCheck();
@@ -183,9 +183,15 @@ interface nsIEditorSpellCheck : nsISuppo
    * compute any suggestions.
    *
    * Watch out: this does not clear any suggestions left over from previous
    * calls to CheckCurrentWord, so there may be suggestions, but they will be
    * invalid.
    */
   boolean       CheckCurrentWordNoSuggest(in wstring suggestedWord);
 
+  /**
+   * Update the dictionary in use to be sure it corresponds to what the editor
+   * needs.
+   */
+  void          UpdateCurrentDictionary(in nsIEditor editor);
+
 };
--- a/editor/idl/nsIHTMLEditor.idl
+++ b/editor/idl/nsIHTMLEditor.idl
@@ -37,26 +37,27 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 #include "domstubs.idl"
 
 interface nsIAtom;
+interface nsIContent;
 interface nsISupportsArray;
 interface nsISelection;
 interface nsIContentFilter;
 
 %{C++
 #define NS_EDITOR_ELEMENT_NOT_FOUND \
   NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_EDITOR, 1)
 
 %}
-[scriptable, uuid(c964b8b0-e9e8-11df-9492-0800200c9a66)]
+[scriptable, uuid(d58f35a7-c269-4292-b9aa-a79e200a7c99)]
 
 interface nsIHTMLEditor : nsISupports
 {
 %{C++
   typedef short EAlignment;
 %}
 
   // used by GetAlignment()
@@ -608,10 +609,16 @@ interface nsIHTMLEditor : nsISupports
    * @return    true if CR in a paragraph creates a new paragraph
    */
   attribute boolean returnInParagraphCreatesNewParagraph;
 
   /**
    * Checks whether a BR node is visible to the user.
    */
   boolean breakIsVisible(in nsIDOMNode aNode);
+
+  /**
+   * Get an active editor's editing host in DOM window.  If this editor isn't
+   * active in the DOM window, this returns NULL.
+   */
+  [noscript, notxpcom] nsIContent GetActiveEditingHost();
 };
 
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -5306,8 +5306,17 @@ nsEditor::BeginKeypressHandling(nsIDOMNS
   NS_ASSERTION(mLastKeypressEventWasTrusted == eTriUnset, "How come our status is not clear?");
 
   if (aEvent) {
     PRBool isTrusted = PR_FALSE;
     aEvent->GetIsTrusted(&isTrusted);
     mLastKeypressEventWasTrusted = isTrusted ? eTriTrue : eTriFalse;
   }
 }
+
+void
+nsEditor::OnFocus(nsIDOMEventTarget* aFocusEventTarget)
+{
+  InitializeSelection(aFocusEventTarget);
+  if (mInlineSpellChecker) {
+    mInlineSpellChecker->UpdateCurrentDictionary();
+  }
+}
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -714,16 +714,21 @@ public:
   // element in the document has focus.
   virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode* aNode);
 
   // Initializes selection and caret for the editor.  If aEventTarget isn't
   // a host of the editor, i.e., the editor doesn't get focus, this does
   // nothing.
   nsresult InitializeSelection(nsIDOMEventTarget* aFocusEventTarget);
 
+  // This method has to be called by nsEditorEventListener::Focus.
+  // All actions that have to be done when the editor is focused needs to be
+  // added here.
+  void OnFocus(nsIDOMEventTarget* aFocusEventTarget);
+
 protected:
 
   PRUint32        mModCount;		// number of modifications (for undo/redo stack)
   PRUint32        mFlags;		// behavior flags. See nsIPlaintextEditor.idl for the flags we use.
 
   nsWeakPtr       mSelConWeak;   // weak reference to the nsISelectionController
   PRInt32         mUpdateCount;
   nsIViewManager::UpdateViewBatch mBatch;
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -813,17 +813,17 @@ nsEditorEventListener::Focus(nsIDOMEvent
 
       nsCOMPtr<nsIDOMElement> element;
       fm->GetFocusedElement(getter_AddRefs(element));
       if (!SameCOMIdentity(element, target))
         return NS_OK;
     }
   }
 
-  mEditor->InitializeSelection(target);
+  mEditor->OnFocus(target);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::Blur(nsIDOMEvent* aEvent)
 {
   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   NS_ENSURE_ARG(aEvent);
--- a/editor/libeditor/html/nsHTMLEditor.h
+++ b/editor/libeditor/html/nsHTMLEditor.h
@@ -453,19 +453,16 @@ protected:
 
   PRBool ShouldReplaceRootElement();
   void ResetRootElementAndEventTarget();
   nsresult GetBodyElement(nsIDOMHTMLElement** aBody);
   // Get the focused node of this editor.
   // @return    If the editor has focus, this returns the focused node.
   //            Otherwise, returns null.
   already_AddRefed<nsINode> GetFocusedNode();
-  // Get an active editor's editing host in DOM window.  If this editor isn't
-  // active in the DOM window, this returns NULL.
-  nsIContent* GetActiveEditingHost();
 
   // Return TRUE if aElement is a table-related elemet and caret was set
   PRBool SetCaretInTableCell(nsIDOMElement* aElement);
   PRBool IsNodeInActiveEditor(nsIDOMNode* aNode);
 
   // key event helpers
   NS_IMETHOD TabInTable(PRBool inIsShift, PRBool *outHandled);
   NS_IMETHOD CreateBR(nsIDOMNode *aNode, PRInt32 aOffset, 
--- a/editor/libeditor/html/tests/test_bug484181.html
+++ b/editor/libeditor/html/tests/test_bug484181.html
@@ -40,39 +40,41 @@ function getSpellCheckSelection() {
   var selcon = editor.selectionController;
   return selcon.getSelection(selcon.SELECTION_SPELLCHECK);  
 }
 
 function append(str) {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
   var edit = document.getElementById("edit");
-  edit.focus();
   var editor = getEditor();
   var sel = editor.selection;
   sel.selectAllChildren(edit);
   sel.collapseToEnd();
 
   for (var i = 0; i < str.length; ++i) {
     synthesizeKey(str[i], {});
   }
 }
 
 function runTest() {
   gMisspeltWords = ["haz", "cheezburger"];
-  is(isSpellingCheckOk(), true, "All misspellings before editing are accounted for.");
-
   var edit = document.getElementById("edit");
-  append(" becaz I'm a lolcat!");
+  edit.focus();
   SimpleTest.executeSoon(function() {
-  gMisspeltWords.push("becaz");
-  gMisspeltWords.push("lolcat");
-  is(isSpellingCheckOk(), true, "All misspellings after typing are accounted for.");
+      is(isSpellingCheckOk(), true, "All misspellings before editing are accounted for.");
 
-  SimpleTest.finish();
+      append(" becaz I'm a lolcat!");
+      SimpleTest.executeSoon(function() {
+      gMisspeltWords.push("becaz");
+      gMisspeltWords.push("lolcat");
+      is(isSpellingCheckOk(), true, "All misspellings after typing are accounted for.");
+
+      SimpleTest.finish();
+      });
   });
 }
 
 function isSpellingCheckOk() {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
   var sel = getSpellCheckSelection();
   var numWords = sel.rangeCount;
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -216,21 +216,26 @@ nsTextEditRules::AfterEdit(PRInt32 actio
     res = mEditor->GetSelection(getter_AddRefs(selection));
     NS_ENSURE_SUCCESS(res, res);
   
     res = mEditor->HandleInlineSpellCheck(action, selection,
                                           mCachedSelectionNode, mCachedSelectionOffset,
                                           nsnull, 0, nsnull, 0);
     NS_ENSURE_SUCCESS(res, res);
 
+    // if only trailing <br> remaining remove it
+    res = RemoveRedundantTrailingBR();
+    if (NS_FAILED(res))
+      return res;
+
     // detect empty doc
     res = CreateBogusNodeIfNeeded(selection);
     NS_ENSURE_SUCCESS(res, res);
     
-    // insure trailing br node
+    // ensure trailing br node
     res = CreateTrailingBRIfNeeded();
     NS_ENSURE_SUCCESS(res, res);
 
     // collapse the selection to the trailing BR if it's at the end of our text node
     CollapseSelectionToTrailingBRIfNeeded(selection);
   }
   return res;
 }
@@ -1041,16 +1046,76 @@ nsTextEditRules::WillOutputText(nsISelec
 
 nsresult
 nsTextEditRules::DidOutputText(nsISelection *aSelection, nsresult aResult)
 {
   return NS_OK;
 }
 
 nsresult
+nsTextEditRules::RemoveRedundantTrailingBR()
+{
+  // If the bogus node exists, we have no work to do
+  if (mBogusNode)
+    return NS_OK;
+
+  // Likewise, nothing to be done if we could never have inserted a trailing br
+  if (IsSingleLineEditor())
+    return NS_OK;
+
+  nsIDOMNode* body = mEditor->GetRoot();
+  if (!body)
+    return NS_ERROR_NULL_POINTER;
+
+  PRBool hasChildren;
+  nsresult res = body->HasChildNodes(&hasChildren);
+  NS_ENSURE_SUCCESS(res, res);
+
+  if (hasChildren) {
+    nsCOMPtr<nsIDOMNodeList> childList;
+    res = body->GetChildNodes(getter_AddRefs(childList));
+    NS_ENSURE_SUCCESS(res, res);
+
+    if (!childList)
+      return NS_ERROR_NULL_POINTER;
+
+    PRUint32 childCount;
+    res = childList->GetLength(&childCount);
+    NS_ENSURE_SUCCESS(res, res);
+
+    // The trailing br is redundant if it is the only remaining child node
+    if (childCount != 1)
+      return NS_OK;
+
+    nsCOMPtr<nsIDOMNode> child;
+    res = body->GetFirstChild(getter_AddRefs(child));
+    NS_ENSURE_SUCCESS(res, res);
+
+    if (nsTextEditUtils::IsMozBR(child)) {
+      // Rather than deleting this node from the DOM tree we should instead
+      // morph this br into the bogus node
+      nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(child);
+      if (elem) {
+        elem->RemoveAttribute(NS_LITERAL_STRING("type"));
+        NS_ENSURE_SUCCESS(res, res);
+
+        // set mBogusNode to be this <br>
+        mBogusNode = elem;
+ 
+        // give it the bogus node attribute
+        nsCOMPtr<nsIContent> content = do_QueryInterface(elem);
+        content->SetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
+                         kMOZEditorBogusNodeValue, PR_FALSE);
+      }
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
 nsTextEditRules::CreateTrailingBRIfNeeded()
 {
   // but only if we aren't a single line edit field
   if (IsSingleLineEditor())
     return NS_OK;
   nsIDOMNode *body = mEditor->GetRoot();
   NS_ENSURE_TRUE(body, NS_ERROR_NULL_POINTER);
   nsCOMPtr<nsIDOMNode> lastChild;
--- a/editor/libeditor/text/nsTextEditRules.h
+++ b/editor/libeditor/text/nsTextEditRules.h
@@ -200,16 +200,19 @@ protected:
                           nsAString *aOutText, 
                           PRBool   *aOutCancel, 
                           PRBool *aHandled);
 
   nsresult DidOutputText(nsISelection *aSelection, nsresult aResult);
 
 
   // helper functions
+
+  /** check for and replace a redundant trailing break */
+  nsresult RemoveRedundantTrailingBR();
   
   /** creates a trailing break in the text doc if there is not one already */
   nsresult CreateTrailingBRIfNeeded();
   
  /** creates a bogus text node if the document has no editable content */
   nsresult CreateBogusNodeIfNeeded(nsISelection *aSelection);
 
   /** returns a truncated insertion string if insertion would place us
--- a/editor/libeditor/text/tests/Makefile.in
+++ b/editor/libeditor/text/tests/Makefile.in
@@ -68,16 +68,17 @@ include $(topsrcdir)/config/rules.mk
 # on our editor, and the combinations depend on the system.
 ifneq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 _TEST_FILES += \
 		test_texteditor_keyevent_handling.html \
 		$(NULL)
 endif
 
 _CHROME_TEST_FILES = \
+		test_bug483651.html \
 		test_bug636465.xul \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs:: $(_CHROME_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/text/tests/test_bug483651.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Plaintext Editor Test code
+   -
+   - The Initial Developer of the Original Code is
+   - Graeme McCutcheon <graememcc_firefox@graeme-online.co.uk>.
+   - Portions created by the Initial Developer are Copyright (C) 2009
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=483651
+-->
+
+<head>
+  <title>Test for Bug 483651</title>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+
+<body onload="doTest();">
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=483651">Mozilla Bug 483651</a>
+  <p id="display"></p>
+  <div id="content" style="display: none">
+  </div>
+
+  <pre id="test">
+    <script type="application/javascript">
+
+      /** Test for Bug 483651 **/
+
+      SimpleTest.waitForExplicitFinish();
+
+      function doTest() {
+        var t1 = $("t1");
+        var editor = null;
+
+        if (t1 instanceof Components.interfaces.nsIDOMNSEditableElement)
+          editor = t1.editor;
+
+        ok(editor, "able to get editor for the element");
+        t1.focus();
+        synthesizeKey("A", {});
+        synthesizeKey("VK_BACK_SPACE", {});
+
+        try {
+          // Was the trailing br removed?
+          is(editor.documentIsEmpty, true, "trailing <br> correctly removed");
+        } catch (e) {
+          ok(false, "test failed with error "+e);
+        }
+        SimpleTest.finish();
+      }
+   </script>
+  </pre>
+
+  <textarea id="t1" rows="2" columns="80"></textarea>
+</body>
+</html>
--- a/editor/txtsvc/public/nsIInlineSpellChecker.idl
+++ b/editor/txtsvc/public/nsIInlineSpellChecker.idl
@@ -38,17 +38,17 @@
 
 #include "nsISupports.idl"
 #include "domstubs.idl"
 
 interface nsISelection;
 interface nsIEditor;
 interface nsIEditorSpellCheck;
 
-[scriptable, uuid(07be036a-2355-4a92-b150-5c9b7e9fdf2f)]
+[scriptable, uuid(f456dda1-965d-470c-8c55-e51b38e45212)]
 
 interface nsIInlineSpellChecker : nsISupports
 {
   readonly attribute nsIEditorSpellCheck spellChecker;
 
   [noscript] void init(in nsIEditor aEditor);
   [noscript] void cleanup(in boolean aDestroyingFrames);
 
@@ -66,15 +66,16 @@ interface nsIInlineSpellChecker : nsISup
   void spellCheckRange(in nsIDOMRange aSelection);
 
   nsIDOMRange getMisspelledWord(in nsIDOMNode aNode, in long aOffset);
   void replaceWord(in nsIDOMNode aNode, in long aOffset, in AString aNewword);
   void addWordToDictionary(in AString aWord);
   
   void ignoreWord(in AString aWord);
   void ignoreWords([array, size_is(aCount)] in wstring aWordsToIgnore, in unsigned long aCount);
+  void updateCurrentDictionary();
 };
 
 %{C++
 
 #define MOZ_INLINESPELLCHECKER_CONTRACTID "@mozilla.org/spellchecker-inline;1"
 
 %}
--- a/editor/txtsvc/public/nsISpellChecker.h
+++ b/editor/txtsvc/public/nsISpellChecker.h
@@ -137,17 +137,18 @@ public:
    * This name is the same string that is in the list returned
    * by GetDictionaryList().
    */
   NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary) = 0;
 
   /**
    * Tells the spellchecker to use a specific dictionary.
    * @param aDictionary a string that is in the list returned
-   * by GetDictionaryList().
+   * by GetDictionaryList() or an empty string. If aDictionary is 
+   * empty string, spellchecker will be disabled.
    */
   NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsISpellChecker, NS_ISPELLCHECKER_IID)
 
 #endif // nsISpellChecker_h__
 
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -1379,16 +1379,19 @@ nsresult mozInlineSpellChecker::DoSpellC
       if (inExclusion)
         continue;
     }
 
     // check spelling and add to selection if misspelled
     PRBool isMisspelled;
     aWordUtil.NormalizeWord(wordText);
     rv = mSpellCheck->CheckCurrentWordNoSuggest(wordText.get(), &isMisspelled);
+    if (NS_FAILED(rv))
+      continue;
+
     if (isMisspelled) {
       // misspelled words count extra toward the max
       wordsSinceTimeCheck += MISSPELLED_WORD_COUNT_PENALTY;
       AddRange(aSpellCheckSelection, wordRange);
 
       aStatus->mWordCount ++;
       if (aStatus->mWordCount >= mMaxMisspellingsPerCheck ||
           SpellCheckSelectionIsFull())
@@ -1436,16 +1439,33 @@ mozInlineSpellChecker::ResumeCheck(mozIn
   mozInlineSpellWordUtil wordUtil;
   nsresult rv = wordUtil.Init(mEditor);
   if (NS_FAILED(rv))
     return NS_OK; // editor doesn't like us, don't assert
 
   nsCOMPtr<nsISelection> spellCheckSelection;
   rv = GetSpellCheckSelection(getter_AddRefs(spellCheckSelection));
   NS_ENSURE_SUCCESS(rv, rv);
+
+  PRUnichar *currentDictionary = nsnull;
+  rv = mSpellCheck->GetCurrentDictionary(&currentDictionary);
+  if (NS_FAILED(rv)) {
+    // no active dictionary
+    PRInt32 count;
+    spellCheckSelection->GetRangeCount(&count);
+    for (PRInt32 index = count - 1; index >= 0; index--) {
+      nsCOMPtr<nsIDOMRange> checkRange;
+      spellCheckSelection->GetRangeAt(index, getter_AddRefs(checkRange));
+      if (checkRange) {
+        RemoveRange(spellCheckSelection, checkRange);
+      }
+    }
+    return NS_OK; 
+  }
+ 
   CleanupRangesInSelection(spellCheckSelection);
 
   rv = aStatus->FinishInitOnEvent(wordUtil);
   NS_ENSURE_SUCCESS(rv, rv);
   if (! aStatus->mRange)
     return NS_OK; // empty range, nothing to do
 
   PRBool doneChecking = PR_TRUE;
@@ -1728,8 +1748,43 @@ nsresult mozInlineSpellChecker::KeyPress
     case nsIDOMKeyEvent::DOM_VK_PAGE_UP:
     case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN:
       HandleNavigationEvent(PR_TRUE /* force a spelling correction */);
       break;
   }
 
   return NS_OK;
 }
+
+NS_IMETHODIMP mozInlineSpellChecker::UpdateCurrentDictionary()
+{
+  if (!mSpellCheck) {
+    return NS_OK;
+  }
+
+  PRUnichar *previousDictionary = nsnull;
+  nsDependentString previousDictionaryStr;
+  if (NS_SUCCEEDED(mSpellCheck->GetCurrentDictionary(&previousDictionary))) {
+    previousDictionaryStr.Assign(previousDictionary);
+  }
+
+  nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
+  nsresult rv = mSpellCheck->UpdateCurrentDictionary(editor);
+
+  PRUnichar *currentDictionary = nsnull;
+  nsDependentString currentDictionaryStr;
+  if (NS_SUCCEEDED(mSpellCheck->GetCurrentDictionary(&currentDictionary))) {
+    currentDictionaryStr.Assign(currentDictionary);
+  }
+
+  if (!previousDictionary || !currentDictionary || !previousDictionaryStr.Equals(currentDictionaryStr)) {
+      rv = SpellCheckRange(nsnull);
+  }
+
+  if (previousDictionary) {
+     nsMemory::Free(previousDictionary);
+  }
+  if (currentDictionary) {
+     nsMemory::Free(currentDictionary);
+  }
+
+  return rv;
+}
--- a/extensions/spellcheck/src/mozSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozSpellChecker.cpp
@@ -364,16 +364,22 @@ mozSpellChecker::GetCurrentDictionary(ns
 }
 
 NS_IMETHODIMP 
 mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
 {
   nsresult rv;
   nsCString *contractId;
 
+  if (aDictionary.IsEmpty()) {
+    mCurrentEngineContractId = nsnull;
+    mSpellCheckingEngine = nsnull;
+    return NS_OK;
+  }
+
   if (!mDictionariesMap.Get(aDictionary, &contractId)){
     NS_WARNING("Dictionary not found");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!mCurrentEngineContractId || !mCurrentEngineContractId->Equals(*contractId)){
     mSpellCheckingEngine = do_GetService(contractId->get(), &rv);
     if (NS_FAILED(rv))
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -39,17 +39,17 @@ struct {
 } default_features[] = {
   { HB_TAG('c','a','l','t'), DEFAULT_PRIORITY },
   { HB_TAG('c','c','m','p'), FIRST_PRIORITY },
   { HB_TAG('c','l','i','g'), DEFAULT_PRIORITY },
   { HB_TAG('c','s','w','h'), DEFAULT_PRIORITY },
   { HB_TAG('c','u','r','s'), DEFAULT_PRIORITY },
   { HB_TAG('k','e','r','n'), DEFAULT_PRIORITY },
   { HB_TAG('l','i','g','a'), DEFAULT_PRIORITY },
-  { HB_TAG('l','o','c','l'), DEFAULT_PRIORITY },
+  { HB_TAG('l','o','c','l'), FIRST_PRIORITY },
   { HB_TAG('m','a','r','k'), DEFAULT_PRIORITY },
   { HB_TAG('m','k','m','k'), DEFAULT_PRIORITY },
   { HB_TAG('r','l','i','g'), DEFAULT_PRIORITY }
 };
 
 static void
 hb_ot_shape_collect_features (hb_ot_shape_plan_t       *plan,
 			      const hb_segment_properties_t  *props,
--- a/gfx/src/nsCoord.h
+++ b/gfx/src/nsCoord.h
@@ -89,26 +89,26 @@ inline void VERIFY_COORD(nscoord aCoord)
 #endif
 }
 
 inline nscoord NSToCoordRound(float aValue)
 {
 #if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
   return NS_lroundup30(aValue);
 #else
-  return nscoord(NS_floorf(aValue + 0.5f));
+  return nscoord(floorf(aValue + 0.5f));
 #endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
 }
 
 inline nscoord NSToCoordRound(double aValue)
 {
 #if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
   return NS_lroundup30((float)aValue);
 #else
-  return nscoord(NS_floor(aValue + 0.5f));
+  return nscoord(floor(aValue + 0.5f));
 #endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
 }
 
 inline nscoord NSToCoordRoundWithClamp(float aValue)
 {
 #ifndef NS_COORD_IS_FLOAT
   // Bounds-check before converting out of float, to avoid overflow
   NS_WARN_IF_FALSE(aValue <= nscoord_MAX,
@@ -355,22 +355,22 @@ inline float NSCoordToFloat(nscoord aCoo
   return (float)aCoord;
 }
 
 /*
  * Coord Rounding Functions
  */
 inline nscoord NSToCoordFloor(float aValue)
 {
-  return nscoord(NS_floorf(aValue));
+  return nscoord(floorf(aValue));
 }
 
 inline nscoord NSToCoordFloor(double aValue)
 {
-  return nscoord(NS_floor(aValue));
+  return nscoord(floor(aValue));
 }
 
 inline nscoord NSToCoordFloorClamped(float aValue)
 {
 #ifndef NS_COORD_IS_FLOAT
   // Bounds-check before converting out of float, to avoid overflow
   NS_WARN_IF_FALSE(aValue <= nscoord_MAX,
                    "Overflowed nscoord_MAX in conversion to nscoord");
@@ -383,22 +383,22 @@ inline nscoord NSToCoordFloorClamped(flo
     return nscoord_MIN;
   }
 #endif
   return NSToCoordFloor(aValue);
 }
 
 inline nscoord NSToCoordCeil(float aValue)
 {
-  return nscoord(NS_ceilf(aValue));
+  return nscoord(ceilf(aValue));
 }
 
 inline nscoord NSToCoordCeil(double aValue)
 {
-  return nscoord(NS_ceil(aValue));
+  return nscoord(ceil(aValue));
 }
 
 inline nscoord NSToCoordCeilClamped(float aValue)
 {
 #ifndef NS_COORD_IS_FLOAT
   // Bounds-check before converting out of float, to avoid overflow
   NS_WARN_IF_FALSE(aValue <= nscoord_MAX,
                    "Overflowed nscoord_MAX in conversion to nscoord");
@@ -432,42 +432,42 @@ inline nscoord NSToCoordCeilClamped(doub
   return NSToCoordCeil(aValue);
 }
 
 /*
  * Int Rounding Functions
  */
 inline PRInt32 NSToIntFloor(float aValue)
 {
-  return PRInt32(NS_floorf(aValue));
+  return PRInt32(floorf(aValue));
 }
 
 inline PRInt32 NSToIntCeil(float aValue)
 {
-  return PRInt32(NS_ceilf(aValue));
+  return PRInt32(ceilf(aValue));
 }
 
 inline PRInt32 NSToIntRound(float aValue)
 {
   return NS_lroundf(aValue);
 }
 
 inline PRInt32 NSToIntRound(double aValue)
 {
   return NS_lround(aValue);
 }
 
 inline PRInt32 NSToIntRoundUp(float aValue)
 {
-  return PRInt32(NS_floorf(aValue + 0.5f));
+  return PRInt32(floorf(aValue + 0.5f));
 }
 
 inline PRInt32 NSToIntRoundUp(double aValue)
 {
-  return PRInt32(NS_floor(aValue + 0.5));
+  return PRInt32(floor(aValue + 0.5));
 }
 
 /* 
  * App Unit/Pixel conversions
  */
 inline nscoord NSFloatPixelsToAppUnits(float aPixels, float aAppUnitsPerPixel)
 {
   return NSToCoordRoundWithClamp(aPixels * aAppUnitsPerPixel);
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -142,17 +142,17 @@ nsFontMetrics::Init(const nsFont& aFont,
 void
 nsFontMetrics::Destroy()
 {
     mDeviceContext = nsnull;
 }
 
 // XXXTODO get rid of this macro
 #define ROUND_TO_TWIPS(x) (nscoord)floor(((x) * mP2A) + 0.5)
-#define CEIL_TO_TWIPS(x) (nscoord)NS_ceil((x) * mP2A)
+#define CEIL_TO_TWIPS(x) (nscoord)ceil((x) * mP2A)
 
 const gfxFont::Metrics& nsFontMetrics::GetMetrics() const
 {
     return mFontGroup->GetFontAt(0)->GetMetrics();
 }
 
 nscoord
 nsFontMetrics::XHeight()
@@ -189,25 +189,25 @@ nsFontMetrics::GetUnderline(nscoord& aOf
 // GetMaxAscent/GetMaxDescent/GetMaxHeight must contain the
 // text-decoration lines drawable area. See bug 421353.
 // BE CAREFUL for rounding each values. The logic MUST be same as
 // nsCSSRendering::GetTextDecorationRectInternal's.
 
 static gfxFloat ComputeMaxDescent(const gfxFont::Metrics& aMetrics,
                                   gfxFontGroup* aFontGroup)
 {
-    gfxFloat offset = NS_floor(-aFontGroup->GetUnderlineOffset() + 0.5);
+    gfxFloat offset = floor(-aFontGroup->GetUnderlineOffset() + 0.5);
     gfxFloat size = NS_round(aMetrics.underlineSize);
-    gfxFloat minDescent = NS_floor(offset + size + 0.5);
+    gfxFloat minDescent = floor(offset + size + 0.5);
     return NS_MAX(minDescent, aMetrics.maxDescent);
 }
 
 static gfxFloat ComputeMaxAscent(const gfxFont::Metrics& aMetrics)
 {
-    return NS_floor(aMetrics.maxAscent + 0.5);
+    return floor(aMetrics.maxAscent + 0.5);
 }
 
 nscoord
 nsFontMetrics::InternalLeading()
 {
     return ROUND_TO_TWIPS(GetMetrics().internalLeading);
 }
 
--- a/gfx/thebes/gfxCachedTempSurface.cpp
+++ b/gfx/thebes/gfxCachedTempSurface.cpp
@@ -109,17 +109,17 @@ gfxCachedTempSurface::Get(gfxASurface::g
     } else {
       NS_ASSERTION(mType == aSimilarTo->GetType(),
                    "Unexpected surface type change");
     }
   }
 
   PRBool cleared = PR_FALSE;
   if (!mSurface) {
-    mSize = gfxIntSize(PRInt32(NS_ceil(aRect.width)), PRInt32(NS_ceil(aRect.height)));
+    mSize = gfxIntSize(PRInt32(ceil(aRect.width)), PRInt32(ceil(aRect.height)));
     mSurface = aSimilarTo->CreateSimilarSurface(aContentType, mSize);
     if (!mSurface)
       return nsnull;
 
     cleared = PR_TRUE;
 #ifdef DEBUG
     mType = aSimilarTo->GetType();
 #endif
--- a/gfx/thebes/gfxFT2Utils.cpp
+++ b/gfx/thebes/gfxFT2Utils.cpp
@@ -65,21 +65,21 @@ ScaleRoundDesignUnits(FT_Short aDesignMe
 // Pango does similar snapping for underline and strikethrough when fonts are
 // hinted, but nsCSSRendering::GetTextDecorationRectInternal always snaps the
 // top and size of lines.  Optimizing the distance between the line and
 // baseline is probably good for the gap between text and underline, but
 // optimizing the center of the line is better for positioning strikethough.
 static void
 SnapLineToPixels(gfxFloat& aOffset, gfxFloat& aSize)
 {
-    gfxFloat snappedSize = NS_MAX(NS_floor(aSize + 0.5), 1.0);
+    gfxFloat snappedSize = NS_MAX(floor(aSize + 0.5), 1.0);
     // Correct offset for change in size
     gfxFloat offset = aOffset - 0.5 * (aSize - snappedSize);
     // Snap offset
-    aOffset = NS_floor(offset + 0.5);
+    aOffset = floor(offset + 0.5);
     aSize = snappedSize;
 }
 
 void
 gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
                              PRUint32* aSpaceGlyph)
 {
     NS_PRECONDITION(aMetrics != NULL, "aMetrics must not be NULL");
@@ -276,26 +276,26 @@ gfxFT2LockedFace::GetMetrics(gfxFont::Me
     aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent;
 
     // Make the line height an integer number of pixels so that lines will be
     // equally spaced (rather than just being snapped to pixels, some up and
     // some down).  Layout calculates line height from the emHeight +
     // internalLeading + externalLeading, but first each of these is rounded
     // to layout units.  To ensure that the result is an integer number of
     // pixels, round each of the components to pixels.
-    aMetrics->emHeight = NS_floor(emHeight + 0.5);
+    aMetrics->emHeight = floor(emHeight + 0.5);
 
     // maxHeight will normally be an integer, but round anyway in case
     // FreeType is configured differently.
     aMetrics->internalLeading =
-        NS_floor(aMetrics->maxHeight - aMetrics->emHeight + 0.5);
+        floor(aMetrics->maxHeight - aMetrics->emHeight + 0.5);
 
     // Text input boxes currently don't work well with lineHeight
     // significantly less than maxHeight (with Verdana, for example).
-    lineHeight = NS_floor(NS_MAX(lineHeight, aMetrics->maxHeight) + 0.5);
+    lineHeight = floor(NS_MAX(lineHeight, aMetrics->maxHeight) + 0.5);
     aMetrics->externalLeading =
         lineHeight - aMetrics->internalLeading - aMetrics->emHeight;
 
     // Ensure emAscent + emDescent == emHeight
     gfxFloat sum = aMetrics->emAscent + aMetrics->emDescent;
     aMetrics->emAscent = sum > 0.0 ?
         aMetrics->emAscent * aMetrics->emHeight / sum : 0.0;
     aMetrics->emDescent = aMetrics->emHeight - aMetrics->emAscent;
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1586,17 +1586,17 @@ gfxFont::SetupGlyphExtents(gfxContext *a
     aContext->SetMatrix(matrix);
 
     const Metrics& fontMetrics = GetMetrics();
     PRUint32 appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit();
     if (!aNeedTight && extents.x_bearing >= 0 &&
         extents.y_bearing >= -fontMetrics.maxAscent &&
         extents.height + extents.y_bearing <= fontMetrics.maxDescent) {
         PRUint32 appUnitsWidth =
-            PRUint32(NS_ceil((extents.x_bearing + extents.width)*appUnitsPerDevUnit));
+            PRUint32(ceil((extents.x_bearing + extents.width)*appUnitsPerDevUnit));
         if (appUnitsWidth < gfxGlyphExtents::INVALID_WIDTH) {
             aExtents->SetContainedGlyphWidthAppUnits(aGlyphID, PRUint16(appUnitsWidth));
             return;
         }
     }
 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
     if (!aNeedTight) {
         ++gGlyphExtentsSetupFallBackToTight;
@@ -1705,19 +1705,19 @@ static double
 RoundToNearestMultiple(double aValue, double aFraction)
 {
     return floor(aValue/aFraction + 0.5) * aFraction;
 }
 
 void gfxFont::CalculateDerivedMetrics(Metrics& aMetrics)
 {
     aMetrics.maxAscent =
-        NS_ceil(RoundToNearestMultiple(aMetrics.maxAscent, 1/1024.0));
+        ceil(RoundToNearestMultiple(aMetrics.maxAscent, 1/1024.0));
     aMetrics.maxDescent =
-        NS_ceil(RoundToNearestMultiple(aMetrics.maxDescent, 1/1024.0));
+        ceil(RoundToNearestMultiple(aMetrics.maxDescent, 1/1024.0));
 
     if (aMetrics.xHeight <= 0) {
         // only happens if we couldn't find either font metrics
         // or a char to measure;
         // pick an arbitrary value that's better than zero
         aMetrics.xHeight = aMetrics.maxAscent * DEFAULT_XHEIGHT_FACTOR;
     }
 
@@ -1820,23 +1820,23 @@ gfxFont::SanitizeMetrics(gfxFont::Metric
             aMetrics->underlineSize = NS_MAX(aMetrics->maxDescent, 1.0);
         // The max underlineOffset is 1px (the min underlineSize is 1px, and min maxDescent is 0px.)
         aMetrics->underlineOffset = aMetrics->underlineSize - aMetrics->maxDescent;
     }
 
     // If strikeout line is overflowed from the ascent, the line should be resized and moved for
     // that being in the ascent space.
     // Note that the strikeoutOffset is *middle* of the strikeout line position.
-    gfxFloat halfOfStrikeoutSize = NS_floor(aMetrics->strikeoutSize / 2.0 + 0.5);
+    gfxFloat halfOfStrikeoutSize = floor(aMetrics->strikeoutSize / 2.0 + 0.5);
     if (halfOfStrikeoutSize + aMetrics->strikeoutOffset > aMetrics->maxAscent) {
         if (aMetrics->strikeoutSize > aMetrics->maxAscent) {
             aMetrics->strikeoutSize = NS_MAX(aMetrics->maxAscent, 1.0);
-            halfOfStrikeoutSize = NS_floor(aMetrics->strikeoutSize / 2.0 + 0.5);
+            halfOfStrikeoutSize = floor(aMetrics->strikeoutSize / 2.0 + 0.5);
         }
-        gfxFloat ascent = NS_floor(aMetrics->maxAscent + 0.5);
+        gfxFloat ascent = floor(aMetrics->maxAscent + 0.5);
         aMetrics->strikeoutOffset = NS_MAX(halfOfStrikeoutSize, ascent / 2.0);
     }
 
     // If overline is larger than the ascent, the line should be resized.
     if (aMetrics->underlineSize > aMetrics->maxAscent) {
         aMetrics->underlineSize = aMetrics->maxAscent;
     }
 }
@@ -2536,17 +2536,17 @@ gfxFontGroup::InitScriptRun(gfxContext *
                     aTextRun->SetMissingGlyph(index,
                                               SURROGATE_TO_UCS4(aString[index],
                                                                 aString[index+1]));
                     index++;
                 } else {
                     gfxFloat wid = mainFont->SynthesizeSpaceWidth(ch);
                     if (wid >= 0.0) {
                         nscoord advance =
-                            aTextRun->GetAppUnitsPerDevUnit() * NS_floor(wid + 0.5);
+                            aTextRun->GetAppUnitsPerDevUnit() * floor(wid + 0.5);
                         gfxTextRun::CompressedGlyph g;
                         if (gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance)) {
                             aTextRun->SetSimpleGlyph(index,
                                                      g.SetSimpleGlyph(advance,
                                                          mainFont->GetSpaceGlyph()));
                         } else {
                             gfxTextRun::DetailedGlyph detailedGlyph;
                             detailedGlyph.mGlyphID = mainFont->GetSpaceGlyph();
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -1123,17 +1123,17 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxC
             charStart = charEnd;
             continue;
         }
 
         // Check if it's a simple one-to-one mapping
         hb_position_t x_advance = posInfo[glyphStart].x_advance;
         nscoord advance =
             roundX ? dev2appUnits * FixedToIntRound(x_advance)
-            : NS_floor(hb2appUnits * x_advance + 0.5);
+            : floor(hb2appUnits * x_advance + 0.5);
 
         if (glyphsInClump == 1 &&
             gfxTextRun::CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
             gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
             aTextRun->IsClusterStart(aTextRunOffset + baseCharIndex) &&
             posInfo[glyphStart].x_offset == 0 &&
             posInfo[glyphStart].y_offset == 0 && yPos == 0)
         {
@@ -1153,36 +1153,36 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxC
 
                 // Rounding offsets independently of advances on the assumption
                 // that clusters use offsets and rounding of offsets should
                 // not accumulate, and that advances are typically between
                 // clusters.
                 hb_position_t x_offset = posInfo[glyphStart].x_offset;
                 details->mXOffset =
                     roundX ? dev2appUnits * FixedToIntRound(x_offset)
-                    : NS_floor(hb2appUnits * x_offset + 0.5);
+                    : floor(hb2appUnits * x_offset + 0.5);
                 hb_position_t y_offset = posInfo[glyphStart].y_offset;
                 details->mYOffset = yPos -
                     (roundY ? dev2appUnits * FixedToIntRound(y_offset)
-                     : NS_floor(hb2appUnits * y_offset + 0.5));
+                     : floor(hb2appUnits * y_offset + 0.5));
 
                 details->mAdvance = advance;
                 hb_position_t y_advance = posInfo[glyphStart].y_advance;
                 if (y_advance != 0) {
                     yPos -=
                         roundY ? dev2appUnits * FixedToIntRound(y_advance)
-                        : NS_floor(hb2appUnits * y_advance + 0.5);
+                        : floor(hb2appUnits * y_advance + 0.5);
                 }
                 if (++glyphStart >= glyphEnd) {
                     break;
                 }
                 x_advance = posInfo[glyphStart].x_advance;
                 advance =
                     roundX ? dev2appUnits * FixedToIntRound(x_advance)
-                    : NS_floor(hb2appUnits * x_advance + 0.5);
+                    : floor(hb2appUnits * x_advance + 0.5);
             }
 
             gfxTextRun::CompressedGlyph g;
             g.SetComplex(aTextRun->IsClusterStart(aTextRunOffset + baseCharIndex),
                          PR_TRUE, detailedGlyphs.Length());
             aTextRun->SetGlyphs(aTextRunOffset + baseCharIndex,
                                 g, detailedGlyphs.Elements());
 
--- a/gfx/thebes/gfxMatrix.h
+++ b/gfx/thebes/gfxMatrix.h
@@ -189,18 +189,18 @@ public:
     }
 
     /**
      * Returns true if the matrix is anything other than a straight
      * translation by integers.
      */
     PRBool HasNonIntegerTranslation() const {
         return HasNonTranslation() ||
-            !FuzzyEqual(x0, NS_floor(x0 + 0.5)) ||
-            !FuzzyEqual(y0, NS_floor(y0 + 0.5));
+            !FuzzyEqual(x0, floor(x0 + 0.5)) ||
+            !FuzzyEqual(y0, floor(y0 + 0.5));
     }
 
     /**
      * Returns true if the matrix has any transform other
      * than a straight translation
      */
     PRBool HasNonTranslation() const {
         return !FuzzyEqual(xx, 1.0) || !FuzzyEqual(yy, 1.0) ||
@@ -286,18 +286,18 @@ public:
         return ((FuzzyEqual(xx, 0.0) && FuzzyEqual(yy, 0.0))
             || (FuzzyEqual(xy, 0.0) && FuzzyEqual(yx, 0.0)));
     }
 
     /**
      * Returns true if the matrix has non-integer scale
      */
     PRBool HasNonIntegerScale() const {
-        return !FuzzyEqual(xx, NS_floor(xx + 0.5)) ||
-               !FuzzyEqual(yy, NS_floor(yy + 0.5));
+        return !FuzzyEqual(xx, floor(xx + 0.5)) ||
+               !FuzzyEqual(yy, floor(yy + 0.5));
     }
 
 private:
     static PRBool FuzzyEqual(gfxFloat aV1, gfxFloat aV2) {
         return fabs(aV2 - aV1) < 1e-6;
     }
 };
 
--- a/gfx/thebes/gfxOS2Fonts.cpp
+++ b/gfx/thebes/gfxOS2Fonts.cpp
@@ -122,21 +122,21 @@ static void FillMetricsDefaults(gfxFont:
     aMetrics->superscriptOffset = aMetrics->xHeight;
     aMetrics->subscriptOffset = aMetrics->xHeight;
 }
 
 // Snap a line to pixels while keeping the center and size of the
 // line as close to the original position as possible.
 static void SnapLineToPixels(gfxFloat& aOffset, gfxFloat& aSize)
 {
-    gfxFloat snappedSize = NS_MAX(NS_floor(aSize + 0.5), 1.0);
+    gfxFloat snappedSize = NS_MAX(floor(aSize + 0.5), 1.0);
     // Correct offset for change in size
     gfxFloat offset = aOffset - 0.5 * (aSize - snappedSize);
     // Snap offset
-    aOffset = NS_floor(offset + 0.5);
+    aOffset = floor(offset + 0.5);
     aSize = snappedSize;
 }
 
 // gfxOS2Font::GetMetrics()
 // return the metrics of the current font using the gfxFont metrics structure.
 // If the metrics are not available yet, compute them using the FreeType
 // function on the font. (This is partly based on the respective function from
 // gfxPangoFonts)
@@ -150,17 +150,17 @@ const gfxFont::Metrics& gfxOS2Font::GetM
     }
 
     // whatever happens below, we can always create the metrics
     mMetrics = new gfxFont::Metrics;
     mSpaceGlyph = 0;
 
     // round size to integer pixels, this is to get full pixels for layout
     // together with internal/external leading (see below)
-    mMetrics->emHeight = NS_floor(GetStyle()->size + 0.5);
+    mMetrics->emHeight = floor(GetStyle()->size + 0.5);
 
     cairo_scaled_font_t* scaledFont = CairoScaledFont();
     if (!scaledFont) {
         FillMetricsDefaults(mMetrics);
         return *mMetrics;
     }
 
     FT_Face face = cairo_ft_scaled_font_lock_face(scaledFont);
@@ -269,19 +269,19 @@ const gfxFont::Metrics& gfxOS2Font::GetM
     mMetrics->maxDescent      = NS_MAX(-face->bbox.yMin * yScale,
                                        mMetrics->emDescent);
     mMetrics->maxAdvance      = NS_MAX(face->max_advance_width * xScale,
                                        mMetrics->aveCharWidth);
 
     // leadings are not available directly (only for WinFNTs);
     // better compute them on our own, to get integer values and make
     // layout happy (see // LockedFTFace::GetMetrics in gfxPangoFonts.cpp)
-    mMetrics->internalLeading = NS_floor(mMetrics->maxHeight
+    mMetrics->internalLeading = floor(mMetrics->maxHeight
                                          - mMetrics->emHeight + 0.5);
-    gfxFloat lineHeight = NS_floor(mMetrics->maxHeight + 0.5);
+    gfxFloat lineHeight = floor(mMetrics->maxHeight + 0.5);
     mMetrics->externalLeading = lineHeight
                               - mMetrics->internalLeading - mMetrics->emHeight;
 
     SanitizeMetrics(mMetrics, PR_FALSE);
 
 #ifdef DEBUG_thebes_1
     printf("gfxOS2Font[%#x]::GetMetrics():\n"
            "  %s (%s)\n"
--- a/gfx/thebes/gfxPoint.h
+++ b/gfx/thebes/gfxPoint.h
@@ -64,15 +64,15 @@ struct THEBES_API gfxPoint : public mozi
     gfxPoint(const nsIntPoint& aPoint) : Super(aPoint.x, aPoint.y) {}
 
     // Round() is *not* rounding to nearest integer if the values are negative.
     // They are always rounding as floor(n + 0.5).
     // See https://bugzilla.mozilla.org/show_bug.cgi?id=410748#c14
     // And if you need similar method which is using NS_round(), you should
     // create new |RoundAwayFromZero()| method.
     gfxPoint& Round() {
-        x = NS_floor(x + 0.5);
-        y = NS_floor(y + 0.5);
+        x = floor(x + 0.5);
+        y = floor(y + 0.5);
         return *this;
     }
 };
 
 #endif /* GFX_POINT_H */
--- a/gfx/thebes/gfxRect.cpp
+++ b/gfx/thebes/gfxRect.cpp
@@ -54,50 +54,50 @@ gfxRect::WithinEpsilonOfIntegerPixels(gf
             WithinEpsilonOfInteger(width, aEpsilon) &&
             WithinEpsilonOfInteger(height, aEpsilon));
 }
 
 void
 gfxRect::Round()
 {
     // Note that don't use NS_round here. See the comment for this method in gfxRect.h
-    gfxFloat x0 = NS_floor(X() + 0.5);
-    gfxFloat y0 = NS_floor(Y() + 0.5);
-    gfxFloat x1 = NS_floor(XMost() + 0.5);
-    gfxFloat y1 = NS_floor(YMost() + 0.5);
+    gfxFloat x0 = floor(X() + 0.5);
+    gfxFloat y0 = floor(Y() + 0.5);
+    gfxFloat x1 = floor(XMost() + 0.5);
+    gfxFloat y1 = floor(YMost() + 0.5);
 
     x = x0;
     y = y0;
 
     width = x1 - x0;
     height = y1 - y0;
 }
 
 void
 gfxRect::RoundIn()
 {
-    gfxFloat x0 = NS_ceil(X());
-    gfxFloat y0 = NS_ceil(Y());
-    gfxFloat x1 = NS_floor(XMost());
-    gfxFloat y1 = NS_floor(YMost());
+    gfxFloat x0 = ceil(X());
+    gfxFloat y0 = ceil(Y());
+    gfxFloat x1 = floor(XMost());
+    gfxFloat y1 = floor(YMost());
 
     x = x0;
     y = y0;
 
     width = x1 - x0;
     height = y1 - y0;
 }
 
 void
 gfxRect::RoundOut()
 {
-    gfxFloat x0 = NS_floor(X());
-    gfxFloat y0 = NS_floor(Y());
-    gfxFloat x1 = NS_ceil(XMost());
-    gfxFloat y1 = NS_ceil(YMost());
+    gfxFloat x0 = floor(X());
+    gfxFloat y0 = floor(Y());
+    gfxFloat x1 = ceil(XMost());
+    gfxFloat y1 = ceil(YMost());
 
     x = x0;
     y = y0;
 
     width = x1 - x0;
     height = y1 - y0;
 }
 
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -484,17 +484,17 @@ gfxUtils::ClampToScaleFactor(gfxFloat aV
   gfxFloat power = log(aVal)/log(kScaleResolution);
 
   // If power is within 1e-6 of an integer, round to nearest to
   // prevent floating point errors, otherwise round up to the
   // next integer value.
   if (fabs(power - NS_round(power)) < 1e-6) {
     power = NS_round(power);
   } else {
-    power = NS_ceil(power);
+    power = ceil(power);
   }
 
   return pow(kScaleResolution, power);
 }
 
 
 /*static*/ void
 gfxUtils::PathFromRegion(gfxContext* aContext, const nsIntRegion& aRegion)
--- a/gfx/thebes/gfxWindowsNativeDrawing.cpp
+++ b/gfx/thebes/gfxWindowsNativeDrawing.cpp
@@ -133,33 +133,33 @@ gfxWindowsNativeDrawing::BeginNativeDraw
             if (mTransformType == TRANSLATION_ONLY || !(mNativeDrawFlags & CAN_AXIS_ALIGNED_SCALE)) {
                 mScale = gfxSize(1.0, 1.0);
 
                 // Add 1 to the surface size; it's guaranteed to not be incorrect,
                 // and it fixes bug 382458
                 // There's probably a better fix, but I haven't figured out
                 // the root cause of the problem.
                 mTempSurfaceSize =
-                    gfxIntSize((PRInt32) NS_ceil(mNativeRect.Width() + 1),
-                               (PRInt32) NS_ceil(mNativeRect.Height() + 1));
+                    gfxIntSize((PRInt32) ceil(mNativeRect.Width() + 1),
+                               (PRInt32) ceil(mNativeRect.Height() + 1));
             } else {
                 // figure out the scale factors
                 mScale = m.ScaleFactors(PR_TRUE);
 
                 mWorldTransform.eM11 = (FLOAT) mScale.width;
                 mWorldTransform.eM12 = 0.0f;
                 mWorldTransform.eM21 = 0.0f;
                 mWorldTransform.eM22 = (FLOAT) mScale.height;
                 mWorldTransform.eDx  = 0.0f;
                 mWorldTransform.eDy  = 0.0f;
 
                 // See comment above about "+1"
                 mTempSurfaceSize =
-                    gfxIntSize((PRInt32) NS_ceil(mNativeRect.Width() * mScale.width + 1),
-                               (PRInt32) NS_ceil(mNativeRect.Height() * mScale.height + 1));
+                    gfxIntSize((PRInt32) ceil(mNativeRect.Width() * mScale.width + 1),
+                               (PRInt32) ceil(mNativeRect.Height() * mScale.height + 1));
             }
         }
     }
 
     if (mRenderState == RENDER_STATE_NATIVE_DRAWING) {
         // we can just do native drawing directly to the context's surface
 
         // do we need to use SetWorldTransform?
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -671,17 +671,17 @@ check-malloc-function-usage: $(filter-ou
 	$(srcdir)/config/check_source_count.py "\bjs_realloc\b" 0 \
 		"in Makefile.in" "cx->realloc_ or rt->realloc_" $^
 	$(srcdir)/config/check_source_count.py "\bjs_free\b" 0 \
 		"in Makefile.in" "cx->free_" $^
 
 	# We desire these numbers to go down, not up. See "User guide to memory
 	# management within SpiderMonkey" in jsutil.h.
 	$(srcdir)/config/check_source_count.py OffTheBooks:: 59 \
-		"in Makefile.in" "{cx,rt}->{new_,new_array,malloc_,calloc_,realloc_}" $^
+		"in Makefile.in" "{cx,rt}->{new_,array_new,malloc_,calloc_,realloc_}" $^
 	# This should go to zero, if possible.
 	$(srcdir)/config/check_source_count.py UnwantedForeground:: 31 \
 		"in Makefile.in" "{cx,rt}->{free_,delete_,array_delete}" $^
 
 ifneq ($(OS_ARCH),WINNT) # FIXME: this should be made work on Windows too.
 check:: check-malloc-function-usage
 endif
 
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -1076,16 +1076,17 @@ else
 	$(QUANTIFY) $(CC) -o $^.quantify $(CFLAGS) $(PROGOBJS) $(LDFLAGS) $(LIBS_DIR) $(LIBS) $(OS_LIBS) $(EXTRA_LIBS)
 endif
 ifndef NO_DIST_INSTALL
 	$(INSTALL) $(IFLAGS2) $^.quantify $(FINAL_TARGET)
 endif
 
 ifdef DTRACE_PROBE_OBJ
 EXTRA_DEPS += $(DTRACE_PROBE_OBJ)
+OBJS += $(DTRACE_PROBE_OBJ)
 endif
 
 $(filter %.$(LIB_SUFFIX),$(LIBRARY)): $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
 	$(RM) $(LIBRARY)
 	$(EXPAND_AR) $(AR_FLAGS) $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS)
 	$(RANLIB) $@
 
 $(filter-out %.$(LIB_SUFFIX),$(LIBRARY)): $(filter %.$(LIB_SUFFIX),$(LIBRARY)) $(OBJS) $(LOBJS) $(SHARED_LIBRARY_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
@@ -1116,18 +1117,18 @@ endif # OS/2
 	$(RM) $@
 	$(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS)
 	$(HOST_RANLIB) $@
 
 ifdef HAVE_DTRACE
 ifndef XP_MACOSX
 ifdef DTRACE_PROBE_OBJ
 ifndef DTRACE_LIB_DEPENDENT
-$(DTRACE_PROBE_OBJ): $(OBJS)
-	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(OBJS)
+$(DTRACE_PROBE_OBJ):
+	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ)
 endif
 endif
 endif
 endif
 
 # On Darwin (Mac OS X), dwarf2 debugging uses debug info left in .o files,
 # so instead of deleting .o files after repacking them into a dylib, we make
 # symlinks back to the originals. The symlinks are a no-op for stabs debugging,
@@ -1139,17 +1140,17 @@ ifndef INCREMENTAL_LINKER
 endif
 ifdef DTRACE_LIB_DEPENDENT
 ifndef XP_MACOSX
 	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o  $(DTRACE_PROBE_OBJ) $(shell $(EXPAND_LIBS) $(MOZILLA_PROBE_LIBS))
 endif
 	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(LOBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(MOZILLA_PROBE_LIBS) $(RESFILE) $(LDFLAGS) $(SHARED_LIBRARY_LIBS) $(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) $(DEF_FILE) $(SHLIB_LDENDFILE)
 	@$(RM) $(DTRACE_PROBE_OBJ)
 else # ! DTRACE_LIB_DEPENDENT
-	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(DTRACE_PROBE_OBJ) $(LOBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(SHARED_LIBRARY_LIBS) $(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) $(DEF_FILE) $(SHLIB_LDENDFILE)
+	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(LOBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(SHARED_LIBRARY_LIBS) $(EXTRA_DSO_LDOPTS) $(OS_LIBS) $(EXTRA_LIBS) $(DEF_FILE) $(SHLIB_LDENDFILE)
 endif # DTRACE_LIB_DEPENDENT
 	@$(call CHECK_STDCXX,$@)
 
 ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
 ifdef MSMANIFEST_TOOL
 ifdef EMBED_MANIFEST_AT
 	@if test -f $@.manifest; then \
 		mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;$(EMBED_MANIFEST_AT); \
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -5017,16 +5017,28 @@ dnl ====================================
 MOZ_ARG_ENABLE_BOOL(gczeal,
 [  --enable-gczeal         Enable zealous GCing],
     JS_GC_ZEAL=1,
     JS_GC_ZEAL= )
 if test -n "$JS_GC_ZEAL"; then
     AC_DEFINE(JS_GC_ZEAL)
 fi
 
+dnl ========================================================
+dnl JS opt-mode assertions and minidump instrumentation
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(js-diagnostics,
+[  --enable-js-diagnostics
+                          Enable JS diagnostic assertions and breakpad data],
+    JS_CRASH_DIAGNOSTICS=1,
+    JS_CRASH_DIAGNOSTICS= )
+if test -n "$JS_CRASH_DIAGNOSTICS"; then
+    AC_DEFINE(JS_CRASH_DIAGNOSTICS)
+fi
+
 dnl ======================================================
 dnl = Enable compiling with ccache
 dnl ======================================================
 MOZ_ARG_WITH_STRING(ccache,
 [  --with-ccache[=path/to/ccache]
                           Enable compiling with ccache],
     CCACHE=$withval, CCACHE="no")
 
--- a/js/src/ctypes/libffi/configure
+++ b/js/src/ctypes/libffi/configure
@@ -11272,17 +11272,17 @@ case "$host" in
 	TARGET=POWERPC; TARGETDIR=powerpc
 	;;
   powerpc-*-darwin*)
 	TARGET=POWERPC_DARWIN; TARGETDIR=powerpc
 	;;
   powerpc-*-aix* | rs6000-*-aix*)
 	TARGET=POWERPC_AIX; TARGETDIR=powerpc
 	;;
-  powerpc-*-freebsd*)
+  powerpc-*-freebsd* | powerpc-*-openbsd*)
 	TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc
 	;;
   powerpc*-*-rtems*)
 	TARGET=POWERPC; TARGETDIR=powerpc
 	;;
 
   s390-*-* | s390x-*-*)
 	TARGET=S390; TARGETDIR=s390
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug678211.js
@@ -0,0 +1,3 @@
+var g = newGlobal('new-compartment');
+g.eval("function f(n) { for (var i = 0; i < n; i++) f(0); }");
+g.f(RUNLOOP + 1);
--- a/js/src/jsapi-tests/Makefile.in
+++ b/js/src/jsapi-tests/Makefile.in
@@ -46,25 +46,28 @@ include $(DEPTH)/config/autoconf.mk
 
 PROGRAM         = jsapi-tests$(BIN_SUFFIX)
 
 CPPSRCS = \
   tests.cpp \
   selfTest.cpp \
   testArgumentsObject.cpp \
   testBug604087.cpp \
+  testChromeBuffer.cpp \
   testClassGetter.cpp \
   testCloneScript.cpp \
   testConservativeGC.cpp \
   testContexts.cpp \
+  testCustomIterator.cpp \
   testDebugger.cpp \
   testDeepFreeze.cpp \
   testDefineGetterSetterNonEnumerable.cpp \
   testDefineProperty.cpp \
   testExtendedEq.cpp \
+  testExternalStrings.cpp \
   testFuncCallback.cpp \
   testFunctionProperties.cpp \
   testGCChunkAlloc.cpp \
   testGetPropertyDefault.cpp \
   testIndexToString.cpp \
   testIntString.cpp \
   testIntern.cpp \
   testLookup.cpp \
@@ -79,19 +82,16 @@ CPPSRCS = \
   testScriptInfo.cpp \
   testScriptObject.cpp \
   testSetProperty.cpp \
   testStringBuffer.cpp \
   testTrap.cpp \
   testUTF8.cpp \
   testVersion.cpp \
   testXDR.cpp \
-  testCustomIterator.cpp \
-  testExternalStrings.cpp \
-  testChromeBuffer.cpp \
   $(NULL)
 
 # Disabled: an entirely unrelated test seems to cause this to fail.  Moreover,
 # given the test's dependence on interactions between the compiler, the GC, and
 # conservative stack scanning, the fix isn't obvious: more investigation
 # needed.
 #CPPSRCS += \
 #  testRegExpInstanceProperties.cpp \
--- a/js/src/jsapi-tests/testIndexToString.cpp
+++ b/js/src/jsapi-tests/testIndexToString.cpp
@@ -2,61 +2,110 @@
  * vim: set ts=8 sw=4 et tw=99:
  */
 
 #include "tests.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsnum.h"
+#include "jsstr.h"
 
 #include "vm/String-inl.h"
 
+template<size_t N> JSFlatString *
+NewString(JSContext *cx, const jschar (&chars)[N])
+{
+    return js_NewStringCopyN(cx, chars, N);
+}
+
+static const struct TestPair {
+    uint32 num;
+    const char *expected;
+} tests[] = {
+    { 0, "0" },
+    { 1, "1" },
+    { 2, "2" },
+    { 9, "9" },
+    { 10, "10" },
+    { 15, "15" },
+    { 16, "16" },
+    { 17, "17" },
+    { 99, "99" },
+    { 100, "100" },
+    { 255, "255" },
+    { 256, "256" },
+    { 257, "257" },
+    { 999, "999" },
+    { 1000, "1000" },
+    { 4095, "4095" },
+    { 4096, "4096" },
+    { 9999, "9999" },
+    { 1073741823, "1073741823" },
+    { 1073741824, "1073741824" },
+    { 1073741825, "1073741825" },
+    { 2147483647, "2147483647" },
+    { 2147483648, "2147483648" },
+    { 2147483649, "2147483649" },
+    { 4294967294, "4294967294" },
+    { 4294967295, "4294967295" },
+};
+
 BEGIN_TEST(testIndexToString)
 {
-    const struct TestPair {
-        uint32 num;
-        const char *expected;
-    } tests[] = {
-        { 0, "0" },
-        { 1, "1" },
-        { 2, "2" },
-        { 9, "9" },
-        { 10, "10" },
-        { 15, "15" },
-        { 16, "16" },
-        { 17, "17" },
-        { 99, "99" },
-        { 100, "100" },
-        { 255, "255" },
-        { 256, "256" },
-        { 257, "257" },
-        { 999, "999" },
-        { 1000, "1000" },
-        { 4095, "4095" },
-        { 4096, "4096" },
-        { 9999, "9999" },
-        { 1073741823, "1073741823" },
-        { 1073741824, "1073741824" },
-        { 1073741825, "1073741825" },
-        { 2147483647, "2147483647" },
-        { 2147483648, "2147483648" },
-        { 2147483649, "2147483649" },
-        { 4294967294, "4294967294" },
-        { 4294967295, "4294967295" },
-    };
-
     for (size_t i = 0, sz = JS_ARRAY_LENGTH(tests); i < sz; i++) {
         uint32 u = tests[i].num;
         JSString *str = js::IndexToString(cx, u);
         CHECK(str);
 
         if (!JSAtom::hasUintStatic(u))
             CHECK(cx->compartment->dtoaCache.lookup(10, u) == str);
 
         JSBool match = JS_FALSE;
         CHECK(JS_StringEqualsAscii(cx, str, tests[i].expected, &match));
         CHECK(match);
     }
 
     return true;
 }
 END_TEST(testIndexToString)
+
+BEGIN_TEST(testStringIsElement)
+{
+    for (size_t i = 0, sz = JS_ARRAY_LENGTH(tests); i < sz; i++) {
+        uint32 u = tests[i].num;
+        JSFlatString *str = js::IndexToString(cx, u);
+        CHECK(str);
+
+        uint32 n;
+        CHECK(str->isElement(&n));
+        CHECK(u == n);
+    }
+
+    return true;
+}
+END_TEST(testStringIsElement)
+
+BEGIN_TEST(testStringToPropertyName)
+{
+    uint32 index;
+
+    static const jschar hiChars[] = { 'h', 'i' };
+    JSFlatString *hiStr = NewString(cx, hiChars);
+    CHECK(hiStr);
+    CHECK(!hiStr->isElement(&index));
+    CHECK(hiStr->toPropertyName(cx) != NULL);
+
+    static const jschar maxChars[] = { '4', '2', '9', '4', '9', '6', '7', '2', '9', '5' };
+    JSFlatString *maxStr = NewString(cx, maxChars);
+    CHECK(maxStr);
+    CHECK(maxStr->isElement(&index));
+    CHECK(index == UINT32_MAX);
+
+    static const jschar maxPlusOneChars[] = { '4', '2', '9', '4', '9', '6', '7', '2', '9', '6' };
+    JSFlatString *maxPlusOneStr = NewString(cx, maxPlusOneChars);
+    CHECK(maxPlusOneStr);
+    CHECK(!maxPlusOneStr->isElement(&index));
+    CHECK(maxPlusOneStr->toPropertyName(cx) != NULL);
+
+    return true;
+}
+END_TEST(testStringToPropertyName)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2713,19 +2713,19 @@ JS_GetGCParameter(JSRuntime *rt, JSGCPar
         return rt->gcMaxMallocBytes;
       case JSGC_STACKPOOL_LIFESPAN:
         return rt->gcEmptyArenaPoolLifespan;
       case JSGC_BYTES:
         return rt->gcBytes;
       case JSGC_MODE:
         return uint32(rt->gcMode);
       case JSGC_UNUSED_CHUNKS:
-        return uint32(rt->gcChunksWaitingToExpire);
+        return uint32(rt->gcEmptyChunkCount);
       case JSGC_TOTAL_CHUNKS:
-        return uint32(rt->gcUserChunkSet.count() + rt->gcSystemChunkSet.count());
+        return uint32(rt->gcChunkSet.count() + rt->gcEmptyChunkCount);
       default:
         JS_ASSERT(key == JSGC_NUMBER);
         return rt->gcNumber;
     }
 }
 
 JS_PUBLIC_API(void)
 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value)
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -164,23 +164,16 @@ js_AtomToPrintableString(JSContext *cx, 
 
 struct JSAtomMap {
     JSAtom **vector;    /* array of ptrs to indexed atoms */
     uint32 length;      /* count of (to-be-)indexed atoms */
 };
 
 namespace js {
 
-/* N.B. must correspond to boolean tagging behavior. */
-enum InternBehavior
-{
-    DoNotInternAtom = false,
-    InternAtom = true
-};
-
 typedef TaggedPointerEntry<JSAtom> AtomStateEntry;
 
 struct AtomHasher
 {
     struct Lookup
     {
         const jschar    *chars;
         size_t          length;
@@ -499,23 +492,16 @@ extern void
 js_SweepAtomState(JSContext *cx);
 
 extern bool
 js_InitCommonAtoms(JSContext *cx);
 
 extern void
 js_FinishCommonAtoms(JSContext *cx);
 
-/*
- * Find or create the atom for a string. Return null on failure to allocate
- * memory.
- */
-extern JSAtom *
-js_AtomizeString(JSContext *cx, JSString *str, js::InternBehavior ib = js::DoNotInternAtom);
-
 extern JSAtom *
 js_Atomize(JSContext *cx, const char *bytes, size_t length,
            js::InternBehavior ib = js::DoNotInternAtom,
            js::FlationCoding fc = js::NormalEncoding);
 
 extern JSAtom *
 js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length,
                 js::InternBehavior ib = js::DoNotInternAtom);
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -130,22 +130,20 @@ js_Int32ToId(JSContext* cx, int32 index,
     if (!str)
         return false;
 
     return js_ValueToStringId(cx, js::StringValue(str), id);
 }
 
 namespace js {
 
-static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1;
-
 /*
  * Write out character representing |index| to the memory just before |end|.
  * Thus |*end| is not touched, but |end[-1]| and earlier are modified as
- * appropriate.  There must be at least UINT32_CHAR_BUFFER_LENGTH elements
+ * appropriate.  There must be at least js::UINT32_CHAR_BUFFER_LENGTH elements
  * before |end| to avoid buffer underflow.  The start of the characters written
  * is returned and is necessarily before |end|.
  */
 template <typename T>
 inline mozilla::RangedPtr<T>
 BackfillIndexInCharBuffer(uint32 index, mozilla::RangedPtr<T> end)
 {
 #ifdef DEBUG
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -133,17 +133,17 @@ struct GSNCache {
 
     jsbytecode      *code;
     Map             map;
 
     GSNCache() : code(NULL) { }
 
     void purge();
 };
- 
+
 inline GSNCache *
 GetGSNCache(JSContext *cx);
 
 struct PendingProxyOperation {
     PendingProxyOperation   *next;
     JSObject                *object;
 };
 
@@ -207,17 +207,17 @@ struct ThreadData {
     PendingProxyOperation *pendingProxyOperation;
 
     ConservativeGCThreadData conservativeGC;
 
     ThreadData();
     ~ThreadData();
 
     bool init();
-    
+
     void mark(JSTracer *trc) {
         stackSpace.mark(trc);
     }
 
     void purge(JSContext *cx) {
         gsnCache.purge();
 
         /* FIXME: bug 506341. */
@@ -258,17 +258,17 @@ struct JSThread {
     /* Factored out of JSThread for !JS_THREADSAFE embedding in JSRuntime. */
     js::ThreadData      data;
 
     JSThread(void *id)
       : id(id),
         suspendCount(0)
 # ifdef DEBUG
       , checkRequestDepth(0)
-# endif        
+# endif
     {
         JS_INIT_CLIST(&contextList);
     }
 
     ~JSThread() {
         /* The thread must have zero contexts. */
         JS_ASSERT(JS_CLIST_IS_EMPTY(&contextList));
     }
@@ -385,28 +385,50 @@ struct JSRuntime
      * See bug 492355 for more details.
      *
      * This comes early in JSRuntime to minimize the immediate format used by
      * trace-JITted code that reads it.
      */
     uint32              protoHazardShape;
 
     /* Garbage collector state, used by jsgc.c. */
-    js::GCChunkSet      gcUserChunkSet;
-    js::GCChunkSet      gcSystemChunkSet;
+
+    /*
+     * Set of all GC chunks with at least one allocated thing. The
+     * conservative GC uses it to quickly check if a possible GC thing points
+     * into an allocated chunk.
+     */
+    js::GCChunkSet      gcChunkSet;
+
+    /*
+     * Doubly-linked lists of chunks from user and system compartments. The GC
+     * allocates its arenas from the corresponding list and when all arenas
+     * in the list head are taken, then the chunk is removed from the list.
+     * During the GC when all arenas in a chunk become free, that chunk is
+     * removed from the list and scheduled for release.
+     */
+    js::gc::Chunk       *gcSystemAvailableChunkListHead;
+    js::gc::Chunk       *gcUserAvailableChunkListHead;
+
+    /*
+     * Singly-linked list of empty chunks and its length. We use the list not
+     * to release empty chunks immediately so they can be used for future
+     * allocations. This avoids very high overhead of chunk release/allocation.
+     */
+    js::gc::Chunk       *gcEmptyChunkListHead;
+    size_t              gcEmptyChunkCount;
 
     js::RootedValueMap  gcRootsHash;
     js::GCLocks         gcLocksHash;
     jsrefcount          gcKeepAtoms;
     uint32              gcBytes;
     uint32              gcTriggerBytes;
     size_t              gcLastBytes;
     size_t              gcMaxBytes;
     size_t              gcMaxMallocBytes;
-    size_t              gcChunksWaitingToExpire;
     uint32              gcEmptyArenaPoolLifespan;
     uint32              gcNumber;
     js::GCMarker        *gcMarkingTracer;
     bool                gcChunkAllocationSinceLastGC;
     int64               gcNextFullGCTime;
     int64               gcJitReleaseTime;
     JSGCMode            gcMode;
     volatile bool       gcIsNeeded;
@@ -667,17 +689,17 @@ struct JSRuntime
 
 #ifdef JSGC_TESTPILOT
         bool        infoEnabled;
 
         bool isTimerEnabled() {
             return infoEnabled;
         }
 
-        /* 
+        /*
          * Circular buffer with GC data.
          * count may grow >= INFO_LIMIT, which would indicate data loss.
          */
         static const size_t INFO_LIMIT = 64;
         JSGCInfo    info[INFO_LIMIT];
         size_t      start;
         size_t      count;
 #else /* defined(MOZ_GCTIMER) */
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -122,17 +122,16 @@ JSCompartment::~JSCompartment()
     for (size_t i = 0; i != JS_ARRAY_LENGTH(scriptsToGC); ++i)
         JS_ASSERT(!scriptsToGC[i]);
 #endif
 }
 
 bool
 JSCompartment::init()
 {
-    chunk = NULL;
     for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
         arenas[i].init();
     freeLists.init();
     if (!crossCompartmentWrappers.init())
         return false;
 
     if (!scriptFilenameTable.init())
         return false;
@@ -462,18 +461,16 @@ JSCompartment::markCrossCompartmentWrapp
 
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront())
         MarkValue(trc, e.front().key, "cross-compartment wrapper");
 }
 
 void
 JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
 {
-    chunk = NULL;
-
     /* Remove dead wrappers from the table. */
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
         JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key.toGCThing()) &&
                      !IsAboutToBeFinalized(cx, e.front().value.toGCThing()),
                      e.front().key.isString());
         if (IsAboutToBeFinalized(cx, e.front().key.toGCThing()) ||
             IsAboutToBeFinalized(cx, e.front().value.toGCThing())) {
             e.removeFront();
@@ -557,18 +554,16 @@ JSCompartment::purge(JSContext *cx)
      * which will eventually abort any current recording.
      */
     if (cx->runtime->gcRegenShapes)
         if (hasTraceMonitor())
             traceMonitor()->needFlush = JS_TRUE;
 #endif
 
 #ifdef JS_METHODJIT
-    js::CheckCompartmentScripts(this);
-
     for (JSScript *script = (JSScript *)scripts.next;
          &script->links != &scripts;
          script = (JSScript *)script->links.next) {
         if (script->hasJITCode()) {
 # if defined JS_POLYIC
             mjit::ic::PurgePICs(cx, script);
 # endif
 # if defined JS_MONOIC
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -385,17 +385,16 @@ typedef HashSet<ScriptFilenameEntry *,
                 ScriptFilenameHasher,
                 SystemAllocPolicy> ScriptFilenameTable;
 
 } /* namespace js */
 
 struct JS_FRIEND_API(JSCompartment) {
     JSRuntime                    *rt;
     JSPrincipals                 *principals;
-    js::gc::Chunk                *chunk;
 
     js::gc::ArenaList            arenas[js::gc::FINALIZE_LIMIT];
     js::gc::FreeLists            freeLists;
 
     uint32                       gcBytes;
     uint32                       gcTriggerBytes;
     size_t                       gcLastBytes;
 
--- a/js/src/jscrashreport.cpp
+++ b/js/src/jscrashreport.cpp
@@ -240,47 +240,47 @@ Ring::copyBytes(void *data, size_t size)
 }
 
 static bool gInitialized;
 
 static Stack gGCStack(JS_CRASH_STACK_GC);
 static Stack gErrorStack(JS_CRASH_STACK_ERROR);
 static Ring gRingBuffer(JS_CRASH_RING);
 
+void
+SnapshotGCStack()
+{
+    if (gInitialized)
+        gGCStack.snapshot();
+}
+
+void
+SnapshotErrorStack()
+{
+    if (gInitialized)
+        gErrorStack.snapshot();
+}
+
+void
+SaveCrashData(uint64 tag, void *ptr, size_t size)
+{
+    if (gInitialized)
+        gRingBuffer.push(tag, ptr, size);
+}
+
 } /* namespace crash */
 } /* namespace js */
 
 using namespace js;
 using namespace js::crash;
 
-JS_FRIEND_API(void)
-js_SnapshotGCStack()
-{
-    if (gInitialized)
-        gGCStack.snapshot();
-}
-
-JS_FRIEND_API(void)
-js_SnapshotErrorStack()
-{
-    if (gInitialized)
-        gErrorStack.snapshot();
-}
-
-JS_FRIEND_API(void)
-js_SaveCrashData(uint64 tag, void *ptr, size_t size)
-{
-    if (gInitialized)
-        gRingBuffer.push(tag, ptr, size);
-}
-
 JS_PUBLIC_API(void)
 JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback)
 {
-#if 1
+#ifdef JS_CRASH_DIAGNOSTICS
     if (!gInitialized) {
         gInitialized = true;
         (*callback)(&gGCStack, sizeof(gGCStack));
         (*callback)(&gErrorStack, sizeof(gErrorStack));
         (*callback)(&gRingBuffer, sizeof(gRingBuffer));
     }
 #endif
 }
--- a/js/src/jscrashreport.h
+++ b/js/src/jscrashreport.h
@@ -37,23 +37,51 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jscrashreport_h___
 #define jscrashreport_h___
 
 #include "jstypes.h"
+#include "jsutil.h"
 
-JS_BEGIN_EXTERN_C
+namespace js {
+namespace crash {
+
+void
+SnapshotGCStack();
 
-JS_FRIEND_API(void)
-js_SnapshotGCStack();
+void
+SnapshotErrorStack();
+
+void
+SaveCrashData(uint64 tag, void *ptr, size_t size);
+
+template<size_t size, char marker>
+class StackBuffer {
+  private:
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+    volatile char buffer[size + 4];
 
-JS_FRIEND_API(void)
-js_SnapshotErrorStack();
+  public:
+    StackBuffer(void *data JS_GUARD_OBJECT_NOTIFIER_PARAM) {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+
+        buffer[0] = marker;
+        buffer[1] = '[';
 
-JS_FRIEND_API(void)
-js_SaveCrashData(uint64 tag, void *ptr, size_t size);
+        for (size_t i = 0; i < size; i++) {
+            if (data)
+                buffer[i + 2] = ((char *)data)[i];
+            else
+                buffer[i + 2] = 0;
+        }
 
-JS_END_EXTERN_C
+        buffer[size - 2] = ']';
+        buffer[size - 1] = marker;
+    }
+};
+
+} /* namespace crash */
+} /* namespace js */
 
 #endif /* jscrashreport_h___ */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -236,17 +236,17 @@ Arena::finalize(JSContext *cx)
                     newListTail->last = thing - sizeof(T);
                     newListTail = newListTail->nextSpanUnchecked(sizeof(T));
                     newFreeSpanStart = 0;
                 }
             } else {
                 if (!newFreeSpanStart)
                     newFreeSpanStart = thing;
                 t->finalize(cx);
-                memset(t, JS_FREE_PATTERN, sizeof(T));
+                JS_POISON(t, JS_FREE_PATTERN, sizeof(T));
             }
         }
     }
 
     if (allClear) {
         JS_ASSERT(newListTail == &newListHead);
         JS_ASSERT(newFreeSpanStart == thingsStart(sizeof(T)));
         return true;
@@ -332,50 +332,75 @@ Chunk::init(JSRuntime *rt)
         *prevp = &a->aheader;
         a->aheader.setAsNotAllocated();
         prevp = &a->aheader.next;
     }
     *prevp = NULL;
 
     for (size_t i = 0; i != JS_ARRAY_LENGTH(markingDelay); ++i)
         markingDelay[i].init();
+
+    /*
+     * The rest of info fields is initailzied in PickChunk. We do not clear
+     * the mark bitmap as that is done at the start of the next GC.
+     */
 }
 
-bool
-Chunk::unused()
+inline Chunk **
+GetAvailableChunkList(JSCompartment *comp)
 {
-    return info.numFree == ArenasPerChunk;
+    JSRuntime *rt = comp->rt;
+    return comp->isSystemCompartment
+           ? &rt->gcSystemAvailableChunkListHead
+           : &rt->gcUserAvailableChunkListHead;
 }
 
-bool
-Chunk::hasAvailableArenas()
+inline void
+Chunk::addToAvailableList(JSCompartment *comp)
 {
-    return info.numFree > 0;
+    Chunk **listHeadp = GetAvailableChunkList(comp);
+    JS_ASSERT(!info.prevp);
+    JS_ASSERT(!info.next);
+    info.prevp = listHeadp;
+    Chunk *head = *listHeadp;
+    if (head) {
+        JS_ASSERT(head->info.prevp == listHeadp);
+        head->info.prevp = &info.next;
+    }
+    info.next = head;
+    *listHeadp = this;
 }
 
-bool
-Chunk::withinArenasRange(Cell *cell)
+inline void
+Chunk::removeFromAvailableList()
 {
-    uintptr_t addr = uintptr_t(cell);
-    if (addr >= uintptr_t(&arenas[0]) && addr < uintptr_t(&arenas[ArenasPerChunk]))
-        return true;
-    return false;
+    JS_ASSERT(info.prevp);
+    *info.prevp = info.next;
+    if (info.next) {
+        JS_ASSERT(info.next->info.prevp == &info.next);
+        info.next->info.prevp = info.prevp;
+    }
+    info.prevp = NULL;
+    info.next = NULL;
 }
 
 template <size_t thingSize>
 ArenaHeader *
 Chunk::allocateArena(JSContext *cx, unsigned thingKind)
 {
     JSCompartment *comp = cx->compartment;
     JS_ASSERT(hasAvailableArenas());
     ArenaHeader *aheader = info.emptyArenaListHead;
     info.emptyArenaListHead = aheader->next;
     aheader->init(comp, thingKind, thingSize);
     --info.numFree;
 
+    if (!hasAvailableArenas())
+        removeFromAvailableList();
+
     JSRuntime *rt = info.runtime;
     Probes::resizeHeap(comp, rt->gcBytes, rt->gcBytes + ArenaSize);
     JS_ATOMIC_ADD(&rt->gcBytes, ArenaSize);
     JS_ATOMIC_ADD(&comp->gcBytes, ArenaSize);
     if (comp->gcBytes >= comp->gcTriggerBytes)
         TriggerCompartmentGC(comp);
 
     return aheader;
@@ -404,18 +429,37 @@ Chunk::releaseArena(ArenaHeader *aheader
 #endif
     JS_ATOMIC_ADD(&rt->gcBytes, -int32(ArenaSize));
     JS_ATOMIC_ADD(&comp->gcBytes, -int32(ArenaSize));
 
     aheader->setAsNotAllocated();
     aheader->next = info.emptyArenaListHead;
     info.emptyArenaListHead = aheader;
     ++info.numFree;
-    if (unused())
+    if (info.numFree == 1) {
+        JS_ASSERT(!info.prevp);
+        JS_ASSERT(!info.next);
+        addToAvailableList(aheader->compartment);
+    } else if (!unused()) {
+        JS_ASSERT(info.prevp);
+    } else {
+        rt->gcChunkSet.remove(this);
+        removeFromAvailableList();
+
+        /*
+         * We keep empty chunks until we are done with finalization to allow
+         * calling IsAboutToBeFinalized/Cell::isMarked for finalized GC things
+         * in empty chunks. So we add the chunk to the empty set even during
+         * GC_SHRINK.
+         */
         info.age = 0;
+        info.next = rt->gcEmptyChunkListHead;
+        rt->gcEmptyChunkListHead = this;
+        rt->gcEmptyChunkCount++;
+    }
 }
 
 inline Chunk *
 AllocateGCChunk(JSRuntime *rt)
 {
     Chunk *p = (Chunk *)rt->gcChunkAllocator->alloc();
 #ifdef MOZ_GCTIMER
     if (p)
@@ -432,110 +476,81 @@ ReleaseGCChunk(JSRuntime *rt, Chunk *p)
     JS_ATOMIC_INCREMENT(&destroyChunkCount);
 #endif
     rt->gcChunkAllocator->free_(p);
 }
 
 inline Chunk *
 PickChunk(JSContext *cx)
 {
-    Chunk *chunk = cx->compartment->chunk;
-    if (chunk && chunk->hasAvailableArenas())
+    JSCompartment *comp = cx->compartment;
+    JSRuntime *rt = comp->rt;
+    Chunk **listHeadp = GetAvailableChunkList(comp);
+    Chunk *chunk = *listHeadp;
+    if (chunk)
         return chunk;
 
-    JSRuntime *rt = cx->runtime;
-    bool isSystemCompartment = cx->compartment->isSystemCompartment;
-
     /*
-     * The chunk used for the last allocation is full, search all chunks for
-     * free arenas.
+     * We do not have available chunks, either get one from the empty set or
+     * allocate one.
      */
-    GCChunkSet::Range
-        r(isSystemCompartment ? rt->gcSystemChunkSet.all() : rt->gcUserChunkSet.all());
-    for (; !r.empty(); r.popFront()) {
-        chunk = r.front();
-        if (chunk->hasAvailableArenas()) {
-            cx->compartment->chunk = chunk;
-            return chunk;
-        }
-    }
-
-    chunk = AllocateGCChunk(rt);
-    if (!chunk) {
-        /* Our last chance is to find an empty chunk in the other chunk set. */
-        GCChunkSet::Enum e(isSystemCompartment ? rt->gcUserChunkSet : rt->gcSystemChunkSet);
-        for (; !e.empty(); e.popFront()) {
-            if (e.front()->info.numFree == ArenasPerChunk) {
-                chunk = e.front();
-                e.removeFront();
-                break;
-            }
-        }
-
+    chunk = rt->gcEmptyChunkListHead;
+    if (chunk) {
+        JS_ASSERT(chunk->unused());
+        JS_ASSERT(!rt->gcChunkSet.has(chunk));
+        JS_ASSERT(rt->gcEmptyChunkCount >= 1);
+        rt->gcEmptyChunkListHead = chunk->info.next;
+        rt->gcEmptyChunkCount--;
+    } else {
+        chunk = AllocateGCChunk(rt);
         if (!chunk)
             return NULL;
+
+        chunk->init(rt);
+        rt->gcChunkAllocationSinceLastGC = true;
     }
 
     /*
      * FIXME bug 583732 - chunk is newly allocated and cannot be present in
      * the table so using ordinary lookupForAdd is suboptimal here.
      */
-    GCChunkSet::AddPtr p = isSystemCompartment ?
-                           rt->gcSystemChunkSet.lookupForAdd(chunk) :
-                           rt->gcUserChunkSet.lookupForAdd(chunk);
+    GCChunkSet::AddPtr p = rt->gcChunkSet.lookupForAdd(chunk);
     JS_ASSERT(!p);
-    if (isSystemCompartment) {
-        if (!rt->gcSystemChunkSet.add(p, chunk)) {
-            ReleaseGCChunk(rt, chunk);
-            return NULL;
-        }
-    } else {
-        if (!rt->gcUserChunkSet.add(p, chunk)) {
-            ReleaseGCChunk(rt, chunk);
-            return NULL;
-        }
+    if (!rt->gcChunkSet.add(p, chunk)) {
+        ReleaseGCChunk(rt, chunk);
+        return NULL;
     }
 
-    chunk->init(rt);
-    cx->compartment->chunk = chunk;
-    rt->gcChunkAllocationSinceLastGC = true;
+    chunk->info.prevp = NULL;
+    chunk->info.next = NULL;
+    chunk->addToAvailableList(comp);
+
     return chunk;
 }
 
 static void
 ExpireGCChunks(JSRuntime *rt, JSGCInvocationKind gckind)
 {
-    static const size_t MaxAge = 3;
-
-    /* Remove unused chunks. */
     AutoLockGC lock(rt);
 
-    rt->gcChunksWaitingToExpire = 0;
-    for (GCChunkSet::Enum e(rt->gcUserChunkSet); !e.empty(); e.popFront()) {
-        Chunk *chunk = e.front();
-        JS_ASSERT(chunk->info.runtime == rt);
-        if (chunk->unused()) {
-            if (gckind == GC_SHRINK || chunk->info.age++ > MaxAge) {
-                e.removeFront();
-                ReleaseGCChunk(rt, chunk);
-                continue;
-            }
-            rt->gcChunksWaitingToExpire++;
-        }
-    }
-    for (GCChunkSet::Enum e(rt->gcSystemChunkSet); !e.empty(); e.popFront()) {
-        Chunk *chunk = e.front();
-        JS_ASSERT(chunk->info.runtime == rt);
-        if (chunk->unused()) {
-            if (gckind == GC_SHRINK || chunk->info.age++ > MaxAge) {
-                e.removeFront();
-                ReleaseGCChunk(rt, chunk);
-                continue;
-            }
-            rt->gcChunksWaitingToExpire++;
+    /* Return old empty chunks to the system. */
+    for (Chunk **chunkp = &rt->gcEmptyChunkListHead; *chunkp; ) {
+        JS_ASSERT(rt->gcEmptyChunkCount);
+        Chunk *chunk = *chunkp;
+        JS_ASSERT(chunk->unused());
+        JS_ASSERT(!rt->gcChunkSet.has(chunk));
+        JS_ASSERT(chunk->info.age <= MAX_EMPTY_CHUNK_AGE);
+        if (gckind == GC_SHRINK || chunk->info.age == MAX_EMPTY_CHUNK_AGE) {
+            *chunkp = chunk->info.next;
+            --rt->gcEmptyChunkCount;
+            ReleaseGCChunk(rt, chunk);
+        } else {
+            /* Keep the chunk but increase its age. */
+            ++chunk->info.age;
+            chunkp = &chunk->info.next;
         }
     }
 }
 
 JS_FRIEND_API(bool)
 IsAboutToBeFinalized(JSContext *cx, const void *thing)
 {
     if (JSAtom::isStatic(thing))
@@ -565,24 +580,17 @@ js_GCThingIsMarked(void *thing, uintN co
  * JIT code is discarded in inactive compartments, regardless of how often that
  * code runs.
  */
 static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 120 * 1000 * 1000;
 
 JSBool
 js_InitGC(JSRuntime *rt, uint32 maxbytes)
 {
-    /*
-     * Make room for at least 16 chunks so the table would not grow before
-     * the browser starts up.
-     */
-    if (!rt->gcUserChunkSet.init(16))
-        return false;
-
-    if (!rt->gcSystemChunkSet.init(16))
+    if (!rt->gcChunkSet.init(INITIAL_CHUNK_CAPACITY))
         return false;
 
     if (!rt->gcRootsHash.init(256))
         return false;
 
     if (!rt->gcLocksHash.init(256))
         return false;
 
@@ -714,18 +722,17 @@ MarkIfGCThingWord(JSTracer *trc, jsuword
 #if JS_BITS_PER_WORD == 32
     jsuword addr = w & JSID_PAYLOAD_MASK;
 #elif JS_BITS_PER_WORD == 64
     jsuword addr = w & JSID_PAYLOAD_MASK & JSVAL_PAYLOAD_MASK;
 #endif
 
     Chunk *chunk = Chunk::fromAddress(addr);
 
-    if (!trc->context->runtime->gcUserChunkSet.has(chunk) &&
-        !trc->context->runtime->gcSystemChunkSet.has(chunk))
+    if (!trc->context->runtime->gcChunkSet.has(chunk))
         return CGCT_NOTCHUNK;
 
     /*
      * We query for pointers outside the arena array after checking for an
      * allocated chunk. Such pointers are rare and we want to reject them
      * after doing more likely rejections.
      */
     if (!Chunk::withinArenasRange(addr))
@@ -922,22 +929,28 @@ js_FinishGC(JSRuntime *rt)
     for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) {
         JSCompartment *comp = *c;
         comp->finishArenaLists();
         Foreground::delete_(comp);
     }
     rt->compartments.clear();
     rt->atomsCompartment = NULL;
 
-    for (GCChunkSet::Range r(rt->gcUserChunkSet.all()); !r.empty(); r.popFront())
+    rt->gcSystemAvailableChunkListHead = NULL;
+    rt->gcUserAvailableChunkListHead = NULL;
+    for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
         ReleaseGCChunk(rt, r.front());
-    for (GCChunkSet::Range r(rt->gcSystemChunkSet.all()); !r.empty(); r.popFront())
-        ReleaseGCChunk(rt, r.front());
-    rt->gcUserChunkSet.clear();
-    rt->gcSystemChunkSet.clear();
+    rt->gcChunkSet.clear();
+    for (Chunk *chunk = rt->gcEmptyChunkListHead; chunk; ) {
+        Chunk *next = chunk->info.next;
+        ReleaseGCChunk(rt, chunk);
+        chunk = next;
+    }
+    rt->gcEmptyChunkListHead = NULL;
+    rt->gcEmptyChunkCount = 0;
 
 #ifdef JS_THREADSAFE
     rt->gcHelperThread.finish(rt);
 #endif
 
 #ifdef DEBUG
     if (!rt->gcRootsHash.empty())
         CheckLeakedRoots(rt);
@@ -1083,45 +1096,45 @@ js_MapGCRoots(JSRuntime *rt, JSGCRootMap
     return ct;
 }
 
 void
 JSRuntime::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
 {
     gcLastBytes = lastBytes;
 
-    size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER);
+    size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, GC_ALLOCATION_THRESHOLD);
     float trigger = float(base) * GC_HEAP_GROWTH_FACTOR;
     gcTriggerBytes = size_t(Min(float(gcMaxBytes), trigger));
 }
 
 void
 JSRuntime::reduceGCTriggerBytes(uint32 amount) {
     JS_ASSERT(amount > 0);
     JS_ASSERT(gcTriggerBytes - amount >= 0);
-    if (gcTriggerBytes - amount < GC_ARENA_ALLOCATION_TRIGGER * GC_HEAP_GROWTH_FACTOR)
+    if (gcTriggerBytes - amount < GC_ALLOCATION_THRESHOLD * GC_HEAP_GROWTH_FACTOR)
         return;
     gcTriggerBytes -= amount;
 }
 
 void
 JSCompartment::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
 {
     gcLastBytes = lastBytes;
 
-    size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, GC_ARENA_ALLOCATION_TRIGGER);
+    size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, GC_ALLOCATION_THRESHOLD);
     float trigger = float(base) * GC_HEAP_GROWTH_FACTOR;
     gcTriggerBytes = size_t(Min(float(rt->gcMaxBytes), trigger));
 }
 
 void
 JSCompartment::reduceGCTriggerBytes(uint32 amount) {
     JS_ASSERT(amount > 0);
     JS_ASSERT(gcTriggerBytes - amount >= 0);
-    if (gcTriggerBytes - amount < GC_ARENA_ALLOCATION_TRIGGER * GC_HEAP_GROWTH_FACTOR)
+    if (gcTriggerBytes - amount < GC_ALLOCATION_THRESHOLD * GC_HEAP_GROWTH_FACTOR)
         return;
     gcTriggerBytes -= amount;
 }
 
 namespace js {
 namespace gc {
 
 inline ArenaHeader *
@@ -1927,17 +1940,17 @@ MaybeGC(JSContext *cx)
     }
 
     /*
      * On 32 bit setting gcNextFullGCTime below is not atomic and a race condition
      * could trigger an GC. We tolerate this.
      */
     int64 now = PRMJ_Now();
     if (rt->gcNextFullGCTime && rt->gcNextFullGCTime <= now) {
-        if (rt->gcChunkAllocationSinceLastGC || rt->gcChunksWaitingToExpire) {
+        if (rt->gcChunkAllocationSinceLastGC || rt->gcEmptyChunkListHead) {
             GCREASON(MAYBEGC);
             js_GC(cx, NULL, GC_SHRINK);
         } else {
             rt->gcNextFullGCTime = now + GC_IDLE_FULL_SPAN;
         }
     }
 }
 
@@ -2253,20 +2266,17 @@ MarkAndSweep(JSContext *cx, JSCompartmen
      * Mark phase.
      */
     GCTIMESTAMP(startMark);
     GCMarker gcmarker(cx);
     JS_ASSERT(IS_GC_MARKING_TRACER(&gcmarker));
     JS_ASSERT(gcmarker.getMarkColor() == BLACK);
     rt->gcMarkingTracer = &gcmarker;
 
-    for (GCChunkSet::Range r(rt->gcUserChunkSet.all()); !r.empty(); r.popFront())
-        r.front()->bitmap.clear();
-
-    for (GCChunkSet::Range r(rt->gcSystemChunkSet.all()); !r.empty(); r.popFront())
+    for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
         r.front()->bitmap.clear();
 
     if (comp) {
         for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c)
             (*c)->markCrossCompartmentWrappers(&gcmarker);
     }
 
     MarkRuntime(&gcmarker);
@@ -2394,19 +2404,16 @@ MarkAndSweep(JSContext *cx, JSCompartmen
     if (rt->gcCallback)
         (void) rt->gcCallback(cx, JSGC_FINALIZE_END);
 #ifdef DEBUG_srcnotesize
   { extern void DumpSrcNoteSizeHist();
     DumpSrcNoteSizeHist();
     printf("GC HEAP SIZE %lu\n", (unsigned long)rt->gcBytes);
   }
 #endif
-
-    for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++)
-        js::CheckCompartmentScripts(*c);
 }
 
 #ifdef JS_THREADSAFE
 
 /*
  * If the GC is running and we're called on another thread, wait for this GC
  * activation to finish. We can safely wait here without fear of deadlock (in
  * the case where we are called within a request on another thread's context)
@@ -2688,17 +2695,17 @@ js_GC(JSContext *cx, JSCompartment *comp
         return;
     }
 
     RecordNativeStackTopForGC(cx);
 
     GCCrashData crashData;
     crashData.isRegen = rt->shapeGen & SHAPE_OVERFLOW_BIT;
     crashData.isCompartment = !!comp;
-    js_SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
+    crash::SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
 
     GCTIMER_BEGIN(rt, comp);
 
     struct AutoGCProbe {
         JSCompartment *comp;
         AutoGCProbe(JSCompartment *comp) : comp(comp) {
             Probes::GCStart(comp);
         }
@@ -2739,17 +2746,17 @@ js_GC(JSContext *cx, JSCompartment *comp
          */
     } while (gckind == GC_LAST_CONTEXT && rt->gcPoke);
 
     rt->gcNextFullGCTime = PRMJ_Now() + GC_IDLE_FULL_SPAN;
 
     rt->gcChunkAllocationSinceLastGC = false;
     GCTIMER_END(gckind == GC_LAST_CONTEXT);
 
-    js_SnapshotGCStack();
+    crash::SnapshotGCStack();
 }
 
 namespace js {
 
 class AutoCopyFreeListToArenas {
     JSRuntime *rt;
 
   public:
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -509,18 +509,19 @@ struct MarkingDelay {
      */
     static ArenaHeader *stackBottom() {
         return reinterpret_cast<ArenaHeader *>(ArenaSize);
     }
 };
 
 /* The chunk header (located at the end of the chunk to preserve arena alignment). */
 struct ChunkInfo {
-    Chunk           *link;
     JSRuntime       *runtime;
+    Chunk           *next;
+    Chunk           **prevp;
     ArenaHeader     *emptyArenaListHead;
     size_t          age;
     size_t          numFree;
 };
 
 const size_t BytesPerArena = ArenaSize + ArenaBitmapBytes + sizeof(MarkingDelay);
 const size_t ArenasPerChunk = (GC_CHUNK_SIZE - sizeof(ChunkInfo)) / BytesPerArena;
 
@@ -608,20 +609,34 @@ struct Chunk {
         return offset < ArenasPerChunk * ArenaSize;
     }
 
     static size_t arenaIndex(uintptr_t addr) {
         JS_ASSERT(withinArenasRange(addr));
         return (addr & GC_CHUNK_MASK) >> ArenaShift;
     }
 
+    uintptr_t address() const {
+        uintptr_t addr = reinterpret_cast<uintptr_t>(this);
+        JS_ASSERT(!(addr & GC_CHUNK_MASK));
+        return addr;
+    }
+
     void init(JSRuntime *rt);
-    bool unused();
-    bool hasAvailableArenas();
-    bool withinArenasRange(Cell *cell);
+
+    bool unused() const {
+        return info.numFree == ArenasPerChunk;
+    }
+
+    bool hasAvailableArenas() const {
+        return info.numFree > 0;
+    }
+
+    inline void addToAvailableList(JSCompartment *compartment);
+    inline void removeFromAvailableList();
 
     template <size_t thingSize>
     ArenaHeader *allocateArena(JSContext *cx, unsigned thingKind);
 
     void releaseArena(ArenaHeader *aheader);
 };
 
 JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE);
@@ -745,23 +760,22 @@ Cell::compartment() const
 /*
  * One past the maximum trace kind.
  */
 #define JSTRACE_LIMIT       4
 
 /*
  * Lower limit after which we limit the heap growth
  */
-const size_t GC_ARENA_ALLOCATION_TRIGGER = 30 * js::GC_CHUNK_SIZE;
+const size_t GC_ALLOCATION_THRESHOLD = 30 * 1024 * 1024;
 
 /*
- * A GC is triggered once the number of newly allocated arenas
- * is GC_HEAP_GROWTH_FACTOR times the number of live arenas after
- * the last GC starting after the lower limit of
- * GC_ARENA_ALLOCATION_TRIGGER.
+ * A GC is triggered once the number of newly allocated arenas is
+ * GC_HEAP_GROWTH_FACTOR times the number of live arenas after the last GC
+ * starting after the lower limit of GC_ALLOCATION_THRESHOLD.
  */
 const float GC_HEAP_GROWTH_FACTOR = 3.0f;
 
 /* Perform a Full GC every 20 seconds if MaybeGC is called */
 static const int64 GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
 
 static inline size_t
 GetFinalizableTraceKind(size_t thingKind)
@@ -993,19 +1007,27 @@ struct FreeLists {
             JS_ASSERT(lists[i].isEmpty());
 #endif
     }
 };
 
 extern void *
 RefillFinalizableFreeList(JSContext *cx, unsigned thingKind);
 
-} /* namespace gc */
+/*
+ * Initial allocation size for data structures holding chunks is set to hold
+ * chunks with total capacity of 16MB to avoid buffer resizes during browser
+ * startup.
+ */
+const size_t INITIAL_CHUNK_CAPACITY = 16 * 1024 * 1024 / GC_CHUNK_SIZE;
 
-typedef Vector<gc::Chunk *, 32, SystemAllocPolicy> GCChunks;
+/* The number of GC cycles an empty chunk can survive before been released. */
+const size_t MAX_EMPTY_CHUNK_AGE = 4;
+
+} /* namespace gc */
 
 struct GCPtrHasher
 {
     typedef void *Lookup;
 
     static HashNumber hash(void *key) {
         return HashNumber(uintptr_t(key) >> JS_GCTHING_ZEROBITS);
     }
--- a/js/src/jsgcmark.cpp
+++ b/js/src/jsgcmark.cpp
@@ -95,47 +95,34 @@ static inline void
 PushMarkStack(GCMarker *gcmarker, const Shape *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSShortString *thing);
 
 static inline void
 PushMarkStack(GCMarker *gcmarker, JSString *thing);
 
-static void
-volatile_memcpy(volatile unsigned char *dst, const void *src, size_t n)
-{
-    for (size_t i = 0; i < n; i++)
-        dst[i] = ((char *)src)[i];
-}
-
 template<typename T>
 void
 Mark(JSTracer *trc, T *thing)
 {
     JS_ASSERT(thing);
     JS_ASSERT(JS_IS_VALID_TRACE_KIND(GetGCThingTraceKind(thing)));
     JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
 
     JS_ASSERT(!JSAtom::isStatic(thing));
     JS_ASSERT(thing->isAligned());
 
     JSRuntime *rt = trc->context->runtime;
     JS_ASSERT(thing->compartment());
     JS_ASSERT(thing->compartment()->rt == rt);
 
-    if (rt->gcCheckCompartment && thing->compartment() != rt->gcCheckCompartment &&
-        thing->compartment() != rt->atomsCompartment)
-    {
-        volatile unsigned char dbg[sizeof(T) + 2];
-        dbg[0] = 0xab;
-        dbg[1] = 0xcd;
-        volatile_memcpy(dbg + 2, thing, sizeof(T));
-        JS_Assert("compartment mismatch in GC", __FILE__, __LINE__);
-    }
+    JS_OPT_ASSERT_IF(rt->gcCheckCompartment,
+                     thing->compartment() == rt->gcCheckCompartment ||
+                     thing->compartment() == rt->atomsCompartment);
 
     /*
      * Don't mark things outside a compartment if we are in a per-compartment
      * GC.
      */
     if (!rt->gcCurrentCompartment || thing->compartment() == rt->gcCurrentCompartment) {
         if (IS_GC_MARKING_TRACER(trc))
             PushMarkStack(static_cast<GCMarker *>(trc), thing);
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -149,16 +149,29 @@ js::GetBlockChain(JSContext *cx, StackFr
     if (!fp->isScriptFrame())
         return NULL;
 
     /* Assume that imacros don't affect blockChain */
     jsbytecode *target = fp->hasImacropc() ? fp->imacropc() : fp->pcQuadratic(cx);
 
     JSScript *script = fp->script();
     jsbytecode *start = script->code;
+
+    /*
+     * If the debugger asks for the scope chain at a pc where we are about to
+     * fix it up, advance target past the fixup. See bug 672804.
+     */
+    JSOp op = js_GetOpcode(cx, script, target);
+    while (op == JSOP_NOP || op == JSOP_INDEXBASE || op == JSOP_INDEXBASE1 ||
+           op == JSOP_INDEXBASE2 || op == JSOP_INDEXBASE3 ||
+           op == JSOP_BLOCKCHAIN || op == JSOP_NULLBLOCKCHAIN)
+    {
+        target += js_CodeSpec[op].length;
+        op = js_GetOpcode(cx, script, target);
+    }
     JS_ASSERT(target >= start && target < start + script->length);
 
     JSObject *blockChain = NULL;
     uintN indexBase = 0;
     ptrdiff_t oplen;
     for (jsbytecode *pc = start; pc < target; pc += oplen) {
         JSOp op = js_GetOpcode(cx, script, pc);
         const JSCodeSpec *cs = &js_CodeSpec[op];
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3412,34 +3412,16 @@ CopySlots(JSContext *cx, JSObject *from,
         Value v = from->getSlot(n);
         if (!cx->compartment->wrap(cx, &v))
             return false;
         to->setSlot(n, v);
     }
     return true;
 }
 
-static void
-CheckProxy(JSObject *obj)
-{
-    if (!obj->isProxy())
-        return;
-
-    JSProxyHandler *handler = obj->getProxyHandler();
-    if (handler->isCrossCompartment())
-        return;
-
-    Value priv = obj->getProxyPrivate();
-    if (!priv.isObject())
-        return;
-
-    if (priv.toObject().compartment() != obj->compartment())
-        JS_Assert("compartment mismatch in proxy object", __FILE__, __LINE__);
-}
-
 JSObject *
 JSObject::clone(JSContext *cx, JSObject *proto, JSObject *parent)
 {
     /*
      * We can only clone native objects and proxies. Dense arrays are slowified if
      * we try to clone them.
      */
     if (!isNative()) {
@@ -3467,18 +3449,16 @@ JSObject::clone(JSContext *cx, JSObject 
         if (getClass()->flags & JSCLASS_HAS_PRIVATE)
             clone->setPrivate(getPrivate());
     } else {
         JS_ASSERT(isProxy());
         if (!CopySlots(cx, this, clone))
             return NULL;
     }
 
-    CheckProxy(clone);
-
     return clone;
 }
 
 static void
 TradeGuts(JSObject *a, JSObject *b)
 {
     JS_ASSERT(a->compartment() == b->compartment());
     JS_ASSERT(a->isFunction() == b->isFunction());
@@ -3581,21 +3561,16 @@ JSObject::swap(JSContext *cx, JSObject *
             return false;
         otherClone = other->clone(cx, other->getProto(), other->getParent());
         if (!otherClone || !otherClone->copyPropertiesFrom(cx, other))
             return false;
     }
     TradeGuts(this, otherClone);
     TradeGuts(other, thisClone);
 
-    CheckProxy(this);
-    CheckProxy(other);
-    CheckProxy(thisClone);
-    CheckProxy(otherClone);
-
     return true;
 }
 
 #if JS_HAS_XDR
 
 #define NO_PARENT_INDEX ((uint32)-1)
 
 uint32
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -338,24 +338,24 @@ JSObject::slotsAndStructSize(uint32 nslo
     return sizeof(js::Value) * (ndslots + nfslots)
            + (isFun ? sizeof(JSFunction) : sizeof(JSObject));
 }
 
 inline uint32
 JSObject::getArrayLength() const
 {
     JS_ASSERT(isArray());
-    return (uint32)(size_t) getPrivate();
+    return (uint32)(uintptr_t) getPrivate();
 }
 
 inline void
 JSObject::setArrayLength(uint32 length)
 {
     JS_ASSERT(isArray());
-    setPrivate((void*)(size_t)length);
+    setPrivate((void*)(uintptr_t) length);
 }
 
 inline uint32
 JSObject::getDenseArrayCapacity()
 {
     JS_ASSERT(isDenseArray());
     return numSlots();
 }
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -4962,24 +4962,26 @@ CloneLeftHandSide(JSParseNode *opn, JSTr
     /* If opn is a definition or use, make pn a use. */
     pn->pn_u.name = opn->pn_u.name;
     pn->pn_op = JSOP_SETNAME;
     if (opn->pn_used) {
         JSDefinition *dn = pn->pn_lexdef;
 
         pn->pn_link = dn->dn_uses;
         dn->dn_uses = pn;
-    } else if (opn->pn_defn) {
-        /* We copied some definition-specific state into pn. Clear it out. */
+    } else {
         pn->pn_expr = NULL;
-        pn->pn_cookie.makeFree();
-        pn->pn_dflags &= ~PND_BOUND;
-        pn->pn_defn = false;
-
-        LinkUseToDef(pn, (JSDefinition *) opn, tc);
+        if (opn->pn_defn) {
+            /* We copied some definition-specific state into pn. Clear it out. */
+            pn->pn_cookie.makeFree();
+            pn->pn_dflags &= ~PND_BOUND;
+            pn->pn_defn = false;
+
+            LinkUseToDef(pn, (JSDefinition *) opn, tc);
+        }
     }
     return pn;
 }
 
 JSParseNode *
 Parser::forStatement()
 {
     JSParseNode *pnseq = NULL;
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1179,21 +1179,16 @@ NewProxyObject(JSContext *cx, JSProxyHan
     JS_ASSERT_IF(parent, cx->compartment == parent->compartment());
     bool fun = call || construct;
     Class *clasp;
     if (fun)
         clasp = &FunctionProxyClass;
     else
         clasp = handler->isOuterWindow() ? &OuterWindowProxyClass : &ObjectProxyClass;
 
-    if (!handler->isCrossCompartment() && priv.isObject()) {
-        if (priv.toObject().compartment() != cx->compartment)
-            JS_Assert("compartment mismatch in proxy object", __FILE__, __LINE__);
-    }
-
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
     if (!obj || !obj->ensureInstanceReservedSlots(cx, 0))
         return NULL;
     obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
     obj->setSlot(JSSLOT_PROXY_PRIVATE, priv);
     if (fun) {
         obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
         if (construct) {
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -87,20 +87,16 @@ class JS_FRIEND_API(JSProxyHandler) {
     virtual bool defaultValue(JSContext *cx, JSObject *obj, JSType hint, js::Value *vp);
     virtual void finalize(JSContext *cx, JSObject *proxy);
     virtual void trace(JSTracer *trc, JSObject *proxy);
 
     virtual bool isOuterWindow() {
         return false;
     }
 
-    virtual bool isCrossCompartment() {
-        return false;
-    }
-
     inline void *family() {
         return mFamily;
     }
 };
 
 /* Dispatch point for handlers that executes the appropriate C++ or scripted traps. */
 class JSProxy {
   public:
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -161,16 +161,17 @@ typedef struct JSXDRState        JSXDRSt
 typedef struct JSExceptionState  JSExceptionState;
 typedef struct JSLocaleCallbacks JSLocaleCallbacks;
 typedef struct JSSecurityCallbacks JSSecurityCallbacks;
 typedef struct JSCompartment     JSCompartment;
 typedef struct JSCrossCompartmentCall JSCrossCompartmentCall;
 typedef struct JSStructuredCloneWriter JSStructuredCloneWriter;
 typedef struct JSStructuredCloneReader JSStructuredCloneReader;
 typedef struct JSStructuredCloneCallbacks JSStructuredCloneCallbacks;
+typedef struct JSPropertyName    JSPropertyName;
 
 #ifdef __cplusplus
 typedef class JSWrapper          JSWrapper;
 typedef class JSCrossCompartmentWrapper JSCrossCompartmentWrapper;
 #endif
 
 /* JSClass (and js::ObjectOps where appropriate) function pointer typedefs. */
 
--- a/js/src/jsscan.cpp
+++ b/js/src/jsscan.cpp
@@ -2126,18 +2126,16 @@ TokenStream::getTokenInternal()
   out:
     flags |= TSF_DIRTYLINE;
     tp->pos.end.index = userbuf.addressOfNextRawChar() - linebase;
     tp->type = tt;
     JS_ASSERT(IsTokenSane(tp));
     return tt;
 
   error:
-    JS_ASSERT(cx->isExceptionPending());
-
     /*
      * For erroneous multi-line tokens we won't have changed end.lineno (it'll
      * still be equal to begin.lineno) so we revert end.index to be equal to
      * begin.index + 1 (as if it's a 1-char token) to avoid having inconsistent
      * begin/end positions.  end.index isn't used in error messages anyway.
      */
     flags |= TSF_DIRTYLINE;
     tp->pos.end.index = tp->pos.begin.index + 1;
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -41,16 +41,17 @@
 
 /*
  * JS script operations.
  */
 #include <string.h>
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
+#include "jscrashreport.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsemit.h"
 #include "jsfun.h"
@@ -283,53 +284,35 @@ Bindings::trace(JSTracer *trc)
 {
     if (lastBinding)
         MarkShape(trc, lastBinding, "shape");
 }
 
 } /* namespace js */
 
 static void
-volatile_memcpy(volatile char *dst, void *src, size_t n)
-{
-    for (size_t i = 0; i < n; i++)
-        dst[i] = ((char *)src)[i];
-}
-
-static void
 CheckScript(JSScript *script, JSScript *prev)
 {
-    volatile char dbg1[sizeof(JSScript)], dbg2[sizeof(JSScript)];
+#ifdef JS_CRASH_DIAGNOSTICS
     if (script->cookie1 != JS_SCRIPT_COOKIE || script->cookie2 != JS_SCRIPT_COOKIE) {
-        volatile_memcpy(dbg1, script, sizeof(JSScript));
-        if (prev)
-            volatile_memcpy(dbg2, prev, sizeof(JSScript));
+        crash::StackBuffer<sizeof(JSScript), 0x87> buf1(script);
+        crash::StackBuffer<sizeof(JSScript), 0x88> buf2(prev);
+        JS_OPT_ASSERT(false);
     }
-    JS_OPT_ASSERT(script->cookie1 == JS_SCRIPT_COOKIE && script->cookie2 == JS_SCRIPT_COOKIE);
+#endif
 }
 
 static void
 CheckScriptOwner(JSScript *script, JSObject *owner)
 {
-    if (script->ownerObject != owner) {
-        volatile char scriptData[sizeof(JSScript)];
-        volatile char owner1Data[sizeof(JSObject)], owner2Data[sizeof(JSObject)];
-        volatile char savedOwner[sizeof(JSObject *)];
-
-        volatile_memcpy(scriptData, script, sizeof(JSScript));
-        volatile_memcpy(savedOwner, &owner, sizeof(JSObject *));
-        if (script->ownerObject != JS_NEW_SCRIPT && script->ownerObject != JS_CACHED_SCRIPT)
-            volatile_memcpy(owner1Data, script->ownerObject, sizeof(JSObject));
-        if (owner != JS_NEW_SCRIPT && owner != JS_CACHED_SCRIPT)
-            volatile_memcpy(owner2Data, owner, sizeof(JSObject));
-    }
+#ifdef JS_CRASH_DIAGNOSTICS
     JS_OPT_ASSERT(script->ownerObject == owner);
-
     if (owner != JS_NEW_SCRIPT && owner != JS_CACHED_SCRIPT)
         JS_OPT_ASSERT(script->compartment == owner->compartment());
+#endif
 }
 
 #if JS_HAS_XDR
 
 enum ScriptBits {
     NoScriptRval,
     SavedCallerFun,
     HasSharps,
@@ -976,18 +959,20 @@ JSScript::NewScript(JSContext *cx, uint3
     size += length * sizeof(jsbytecode) +
             nsrcnotes * sizeof(jssrcnote);
 
     script = (JSScript *) cx->malloc_(size);
     if (!script)
         return NULL;
 
     PodZero(script);
+#ifdef JS_CRASH_DIAGNOSTICS
     script->cookie1 = script->cookie2 = JS_SCRIPT_COOKIE;
     script->ownerObject = JS_NEW_SCRIPT;
+#endif
     script->length = length;
     script->version = version;
     new (&script->bindings) Bindings(cx, emptyCallShape);
 
     if (cx->hasRunOption(JSOPTION_PCCOUNT))
         (void) script->pcCounters.init(cx, length);
 
     uint8 *scriptEnd = reinterpret_cast<uint8 *>(script + 1);
@@ -1281,18 +1266,20 @@ JSScript::totalSize()
            length * sizeof(jsbytecode) +
            numNotes() * sizeof(jssrcnote) -
            (uint8 *) this;
 }
 
 void
 JSScript::setOwnerObject(JSObject *owner)
 {
+#ifdef JS_CRASH_DIAGNOSTICS
     CheckScriptOwner(this, JS_NEW_SCRIPT);
     ownerObject = owner;
+#endif
 }
 
 /*
  * Nb: srcnotes are variable-length.  This function computes the number of
  * srcnote *slots*, which may be greater than the number of srcnotes.
  */
 uint32
 JSScript::numNotes()
@@ -1323,32 +1310,16 @@ js_CallDestroyScriptHook(JSContext *cx, 
     JSDestroyScriptHook hook;
 
     hook = cx->debugHooks->destroyScriptHook;
     if (hook)
         hook(cx, script, cx->debugHooks->destroyScriptHookData);
     JS_ClearScriptTraps(cx, script);
 }
 
-namespace js {
-
-void
-CheckCompartmentScripts(JSCompartment *comp)
-{
-    JSScript *prev = NULL;
-    for (JSScript *script = (JSScript *)comp->scripts.next;
-         &script->links != &comp->scripts;
-         prev = script, script = (JSScript *)script->links.next)
-    {
-        CheckScript(script, prev);
-    }
-}
-
-} /* namespace js */
-
 static void
 DestroyScript(JSContext *cx, JSScript *script, JSObject *owner, uint32 caller)
 {
     CheckScript(script, NULL);
     CheckScriptOwner(script, owner);
 
     if (script->principals)
         JSPRINCIPALS_DROP(cx, script->principals);
@@ -1403,17 +1374,17 @@ DestroyScript(JSContext *cx, JSScript *s
 #endif
     JS_REMOVE_LINK(&script->links);
 
     script->pcCounters.destroy(cx);
 
     if (script->sourceMap)
         cx->free_(script->sourceMap);
 
-    memset(script, 0xdb, script->totalSize());
+    JS_POISON(script, 0xdb, sizeof(JSScript));
     *(uint32 *)script = caller;
     cx->free_(script);
 }
 
 void
 js_DestroyScript(JSContext *cx, JSScript *script, uint32 caller)
 {
     JS_ASSERT(!cx->runtime->gcRunning);
@@ -1438,19 +1409,20 @@ js_DestroyCachedScript(JSContext *cx, JS
 
 void
 js_TraceScript(JSTracer *trc, JSScript *script, JSObject *owner)
 {
     CheckScript(script, NULL);
     if (owner)
         CheckScriptOwner(script, owner);
 
+#ifdef JS_CRASH_DIAGNOSTICS
     JSRuntime *rt = trc->context->runtime;
-    if (rt->gcCheckCompartment && script->compartment != rt->gcCheckCompartment)
-        JS_Assert("compartment mismatch in GC", __FILE__, __LINE__);
+    JS_OPT_ASSERT_IF(rt->gcCheckCompartment, script->compartment == rt->gcCheckCompartment);
+#endif
 
     JSAtomMap *map = &script->atomMap;
     MarkAtomRange(trc, map->length, map->vector, "atomMap");
 
     if (JSScript::isValidOffset(script->objectsOffset)) {
         JSObjectArray *objarray = script->objects();
         MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
     }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -444,17 +444,19 @@ struct JSScript {
 
     static JSScript *NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg);
 
     /* FIXME: bug 586181 */
     JSCList         links;      /* Links for compartment script list */
     jsbytecode      *code;      /* bytecodes and their immediate operands */
     uint32          length;     /* length of code vector */
 
+#ifdef JS_CRASH_DIAGNOSTICS
     uint32          cookie1;
+#endif
 
   private:
     uint16          version;    /* JS version under which script was compiled */
 
   public:
     uint16          nfixed;     /* number of slots besides stack operands in
                                    slot array */
   private:
@@ -502,17 +504,19 @@ struct JSScript {
     uint16          staticLevel;/* static level for display maintenance */
     uint16          nClosedArgs; /* number of args which are closed over. */
     uint16          nClosedVars; /* number of vars which are closed over. */
     js::Bindings    bindings;   /* names of top-level variables in this script
                                    (and arguments if this is a function script) */
     JSPrincipals    *principals;/* principals for this script */
     jschar          *sourceMap; /* source map file or null */
 
+#ifdef JS_CRASH_DIAGNOSTICS
     JSObject        *ownerObject;
+#endif
 
     void setOwnerObject(JSObject *owner);
 
     union {
         /*
          * A script object of class js_ScriptClass, to ensure the script is GC'd.
          * - All scripts returned by JSAPI functions (JS_CompileScript,
          *   JS_CompileFile, etc.) have these objects.
@@ -536,17 +540,19 @@ struct JSScript {
     JSThread        *owner;     /* for thread-safe life-cycle assertions */
 #endif
 
     uint32          *closedSlots; /* vector of closed slots; args first, then vars. */
 
     /* array of execution counters for every JSOp in the script, by runmode */
     JSPCCounters    pcCounters;
 
+#ifdef JS_CRASH_DIAGNOSTICS
     uint32          cookie2;
+#endif
 
   public:
 #ifdef JS_METHODJIT
     // Fast-cached pointers to make calls faster. These are also used to
     // quickly test whether there is JIT code; a NULL value means no
     // compilation has been attempted. A JS_UNJITTABLE_SCRIPT value means
     // compilation failed. Any value is the arity-check entry point.
     void *jitArityCheckNormal;
@@ -742,29 +748,16 @@ js_DestroyScriptFromGC(JSContext *cx, JS
  * Script objects may be cached and reused, in which case their JSD-visible
  * lifetimes may be shorter than their actual lifetimes. Destroy one such
  * script for real as part of a GC pass. From JSD's point of view, the script
  * is already dead.
  */
 extern void
 js_DestroyCachedScript(JSContext *cx, JSScript *script);
 
-namespace js {
-
-/*
- * This diagnostic function checks that a compartment's list of scripts
- * contains only valid scripts. It also searches for the target script
- * in the list. If expected is true, it asserts that the target script
- * is found. If expected is false, it asserts that it's not found.
- */
-void
-CheckCompartmentScripts(JSCompartment *comp);
-
-} /* namespace js */
-
 extern void
 js_TraceScript(JSTracer *trc, JSScript *script, JSObject *owner);
 
 extern JSObject *
 js_NewScriptObject(JSContext *cx, JSScript *script);
 
 /*
  * To perturb as little code as possible, we introduce a js_GetSrcNote lookup
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1530,21 +1530,18 @@ MatchCallback(JSContext *cx, RegExpStati
     JSObject *&arrayobj = *static_cast<MatchArgType>(p);
     if (!arrayobj) {
         arrayobj = NewDenseEmptyArray(cx);
         if (!arrayobj)
             return false;
     }
 
     Value v;
-    if (!res->createLastMatch(cx, &v))
-        return false;
-
-    JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
-    return !!arrayobj->setProperty(cx, INT_TO_JSID(count), &v, false);
+    return res->createLastMatch(cx, &v) &&
+           arrayobj->defineProperty(cx, INT_TO_JSID(count), v);
 }
 
 static JSBool
 str_match(JSContext *cx, uintN argc, Value *vp)
 {
     JSString *str = ThisToStringForStringProto(cx, vp);
     if (!str)
         return false;
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -10462,17 +10462,20 @@ TraceRecorder::record_EnterFrame()
 
         setFrameObjPtr(fp->addressOfScopeChain(), call_ins);
     } else {
         setFrameObjPtr(fp->addressOfScopeChain(), scopeChain_ins);
     }
 
     /* Try inlining one level in case this recursion doesn't go too deep. */
     if (fp->script() == fp->prev()->script() &&
-        fp->prev()->prev() && fp->prev()->prev()->script() == fp->script()) {
+        fp->prev()->prev() &&
+        fp->prev()->prev()->isScriptFrame() &&
+        fp->prev()->prev()->script() == fp->script())
+    {
         RETURN_STOP_A("recursion started inlining");
     }
 
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_LeaveFrame()
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -40,39 +40,50 @@
 /*
  * PR assertion checker.
  */
 
 #ifndef jsutil_h___
 #define jsutil_h___
 
 #include "jstypes.h"
-#include "jscrashreport.h"
 #include "mozilla/Util.h"
 #include <stdlib.h>
 #include <string.h>
 
 JS_BEGIN_EXTERN_C
 
 #define JS_CRASH_UNLESS(__cond)                                                 \
     JS_BEGIN_MACRO                                                              \
         if (!(__cond)) {                                                        \
             *(int *)(uintptr_t)0xccadbeef = 0;                                  \
             ((void(*)())0)(); /* More reliable, but doesn't say CCADBEEF */     \
         }                                                                       \
     JS_END_MACRO
 
 #define JS_FREE_PATTERN 0xDA
 
+#ifdef JS_CRASH_DIAGNOSTICS
+
+#define JS_POISON(p, val, size) memset((p), (val), (size))
+
 #define JS_OPT_ASSERT(expr)                                                   \
     ((expr) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
 
 #define JS_OPT_ASSERT_IF(cond, expr)                                          \
     ((!(cond) || (expr)) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
 
+#else
+
+#define JS_POISON(p, val, size) ((void) 0)
+#define JS_OPT_ASSERT(expr) ((void) 0)
+#define JS_OPT_ASSERT_IF(cond, expr) ((void) 0)
+
+#endif /* JS_CRASH_DIAGNOSTICS */
+
 #ifdef DEBUG
 
 #define JS_ASSERT(expr)                                                       \
     ((expr) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
 
 #define JS_ASSERT_IF(cond, expr)                                              \
     ((!(cond) || (expr)) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
 
@@ -222,40 +233,34 @@ extern JS_PUBLIC_DATA(JSUint32) OOM_coun
             return NULL; \
         } \
     } while (0)
 
 #else
 #define JS_OOM_POSSIBLY_FAIL() do {} while(0)
 #endif
 
-static JS_INLINE void *js_record_oom(void *p) {
-    if (!p)
-        js_SnapshotErrorStack();
-    return p;
-}
-
 /*
  * SpiderMonkey code should not be calling these allocation functions directly.
  * Instead, all calls should go through JSRuntime, JSContext or OffTheBooks.
  * However, js_free() can be called directly.
  */
 static JS_INLINE void* js_malloc(size_t bytes) {
     JS_OOM_POSSIBLY_FAIL();
-    return js_record_oom(malloc(bytes));
+    return malloc(bytes);
 }
 
 static JS_INLINE void* js_calloc(size_t bytes) {
     JS_OOM_POSSIBLY_FAIL();
-    return js_record_oom(calloc(bytes, 1));
+    return calloc(bytes, 1);
 }
 
 static JS_INLINE void* js_realloc(void* p, size_t bytes) {
     JS_OOM_POSSIBLY_FAIL();
-    return js_record_oom(realloc(p, bytes));
+    return realloc(p, bytes);
 }
 
 static JS_INLINE void js_free(void* p) {
     free(p);
 }
 #endif/* JS_USE_CUSTOM_ALLOCATOR */
 
 JS_END_EXTERN_C
@@ -266,23 +271,23 @@ JS_END_EXTERN_C
 
 /* 
  * User guide to memory management within SpiderMonkey:
  *
  * Quick tips:
  *
  *   Allocation:
  *   - Prefer to allocate using JSContext:
- *       cx->{malloc_,realloc_,calloc_,new_,new_array}
+ *       cx->{malloc_,realloc_,calloc_,new_,array_new}
  *
  *   - If no JSContext is available, use a JSRuntime:
- *       rt->{malloc_,realloc_,calloc_,new_,new_array}
+ *       rt->{malloc_,realloc_,calloc_,new_,array_new}
  *
  *   - As a last resort, use unaccounted allocation ("OffTheBooks"):
- *       js::OffTheBooks::{malloc_,realloc_,calloc_,new_,new_array}
+ *       js::OffTheBooks::{malloc_,realloc_,calloc_,new_,array_new}
  *
  *   Deallocation:
  *   - When the deallocation occurs on a slow path, use:
  *       Foreground::{free_,delete_,array_delete}
  *
  *   - Otherwise deallocate on a background thread using a JSContext:
  *       cx->{free_,delete_,array_delete}
  *  
--- a/js/src/jsvalue.h
+++ b/js/src/jsvalue.h
@@ -951,16 +951,18 @@ typedef JSType
 (* TypeOfOp)(JSContext *cx, JSObject *obj);
 typedef JSObject *
 (* ObjectOp)(JSContext *cx, JSObject *obj);
 typedef void
 (* FinalizeOp)(JSContext *cx, JSObject *obj);
 
 class AutoIdVector;
 
+class PropertyName;
+
 /*
  * Prepare to make |obj| non-extensible; in particular, fully resolve its properties.
  * On error, return false.
  * If |obj| is now ready to become non-extensible, set |*fixed| to true and return true.
  * If |obj| refuses to become non-extensible, set |*fixed| to false and return true; the
  * caller will throw an appropriate error.
  */
 typedef JSBool
@@ -978,16 +980,19 @@ static inline NewEnumerateOp     Valueif
 static inline JSNewEnumerateOp   Jsvalify(NewEnumerateOp f)     { return (JSNewEnumerateOp)f; }
 static inline HasInstanceOp      Valueify(JSHasInstanceOp f)    { return (HasInstanceOp)f; }
 static inline JSHasInstanceOp    Jsvalify(HasInstanceOp f)      { return (JSHasInstanceOp)f; }
 static inline CheckAccessOp      Valueify(JSCheckAccessOp f)    { return (CheckAccessOp)f; }
 static inline JSCheckAccessOp    Jsvalify(CheckAccessOp f)      { return (JSCheckAccessOp)f; }
 static inline EqualityOp         Valueify(JSEqualityOp f);      /* Same type as JSHasInstanceOp */
 static inline JSEqualityOp       Jsvalify(EqualityOp f);        /* Same type as HasInstanceOp */
 
+static inline PropertyName       *Valueify(JSPropertyName *n)     { return (PropertyName *)n; }
+static inline JSPropertyName     *Jsvalify(PropertyName *n)       { return (JSPropertyName *)n; }
+
 static const PropertyOp       PropertyStub       = (PropertyOp)JS_PropertyStub;
 static const StrictPropertyOp StrictPropertyStub = (StrictPropertyOp)JS_StrictPropertyStub;
 static const JSEnumerateOp    EnumerateStub      = JS_EnumerateStub;
 static const JSResolveOp      ResolveStub        = JS_ResolveStub;
 static const ConvertOp        ConvertStub        = (ConvertOp)JS_ConvertStub;
 static const JSFinalizeOp     FinalizeStub       = JS_FinalizeStub;
 
 #define JS_CLASS_MEMBERS                                                      \
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -394,17 +394,17 @@ ForceFrame::enter()
        return false;
     LeaveTrace(context);
 
     JS_ASSERT(context->compartment == target->compartment());
 
     JSObject *scopeChain = target->getGlobal();
     JS_ASSERT(scopeChain->isNative());
 
-    return context->stack.pushDummyFrame(context, *scopeChain, frame);
+    return context->stack.pushDummyFrame(context, REPORT_ERROR, *scopeChain, frame);
 }
 
 AutoCompartment::AutoCompartment(JSContext *cx, JSObject *target)
     : context(cx),
       origin(cx->compartment),
       target(target),
       destination(target->getCompartment()),
       entered(false)
@@ -423,18 +423,31 @@ AutoCompartment::enter()
     JS_ASSERT(!entered);
     if (origin != destination) {
         LeaveTrace(context);
 
         JSObject *scopeChain = target->getGlobal();
         JS_ASSERT(scopeChain->isNative());
 
         frame.construct();
-        if (!context->stack.pushDummyFrame(context, *scopeChain, &frame.ref()))
+
+        /*
+         * Set the compartment eagerly so that pushDummyFrame associates the
+         * resource allocation request with 'destination' instead of 'origin'.
+         * (This is important when content has overflowed the stack and chrome
+         * is preparing to run JS to throw up a slow script dialog.) However,
+         * if an exception is thrown, we need it to be in origin's compartment
+         * so be careful to only report after restoring.
+         */
+        context->compartment = destination;
+        if (!context->stack.pushDummyFrame(context, DONT_REPORT_ERROR, *scopeChain, &frame.ref())) {
+            context->compartment = origin;
+            js_ReportOverRecursed(context);
             return false;
+        }
 
         if (context->isExceptionPending())
             context->wrapPendingException();
     }
     entered = true;
     return true;
 }
 
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -150,20 +150,16 @@ class JS_FRIEND_API(JSCrossCompartmentWr
                            uintN argc, js::Value *argv, js::Value *rval);
     virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const js::Value *vp, bool *bp);
     virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper);
     virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
     virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, js::Value *vp);
 
     virtual void trace(JSTracer *trc, JSObject *wrapper);
 
-    virtual bool isCrossCompartment() {
-        return true;
-    }
-
     static JSCrossCompartmentWrapper singleton;
 };
 
 namespace js {
 
 // A hacky class that lets a friend force a fake frame. We must already be
 // in the compartment of |target| when we enter the forced frame.
 class JS_FRIEND_API(ForceFrame)
--- a/js/src/tests/ecma_5/String/jstests.list
+++ b/js/src/tests/ecma_5/String/jstests.list
@@ -1,11 +1,12 @@
 url-prefix ../../jsreftest.html?test=ecma_5/String/
 script 15.5.4.2.js
 script 15.5.4.7.js
 script 15.5.4.11-01.js
 script defaultvalue.js
+script match-defines-match-elements.js
 script split-01.js
 script split-undefined-separator.js
 script split-xregexp.js
 script string-object-length.js
 script string-space-trim.js
 script string-upper-lower-mapping.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/String/match-defines-match-elements.js
@@ -0,0 +1,47 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+var BUGNUMBER = 677820;
+var summary =
+  "String.prototype.match must define matches on the returned array, not set " +
+  "them";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var called = false;
+function setterFunction(v) { called = true; }
+function getterFunction(v) { return "getter"; }
+
+Object.defineProperty(Array.prototype, 1,
+  { get: getterFunction, set: setterFunction });
+
+assertEq(called, false);
+var matches = "abcdef".match(/./g);
+assertEq(called, false);
+assertEq(matches.length, 6);
+assertEq(matches[0], "a");
+assertEq(matches[1], "b");
+assertEq(matches[2], "c");
+assertEq(matches[3], "d");
+assertEq(matches[4], "e");
+assertEq(matches[5], "f");
+
+var desc = Object.getOwnPropertyDescriptor(Array.prototype, 1);
+assertEq(desc.get, getterFunction);
+assertEq(desc.set, setterFunction);
+assertEq(desc.enumerable, false);
+assertEq(desc.configurable, false);
+assertEq([][1], "getter");
+
+assertEq(called, false);
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");
--- a/js/src/tests/js1_8_5/extensions/jstests.list
+++ b/js/src/tests/js1_8_5/extensions/jstests.list
@@ -48,9 +48,12 @@ script regress-631723.js
 skip-if(!xulRuntime.shell) script regress-636818.js
 script regress-636697.js
 script regress-637985.js
 script is-generator.js
 script weakmap.js
 script regress-645160.js
 script regress-650753.js
 script regress-668438.js
+require-or(debugMode,skip) script regress-672804-1.js
+require-or(debugMode,skip) script regress-672804-2.js
+require-or(debugMode,skip) script regress-672804-3.js
 script regress-677924.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/regress-672804-1.js
@@ -0,0 +1,12 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var a = 0;
+function f() {
+    let (a = let (x = 1) x) {}
+}
+
+trap(f, 3, 'assertEq(evalInFrame(1, "a"), 0)');
+f();
+
+reportCompare(0, 0, 'ok');
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/regress-672804-2.js
@@ -0,0 +1,12 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var a = 0;
+function f() {
+    let (a = let (x = 1) x) {}
+}
+
+trap(f, 4, 'assertEq(evalInFrame(1, "a"), 0)');
+f();
+
+reportCompare(0, 0, 'ok');
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/regress-672804-3.js
@@ -0,0 +1,11 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var e = [], x = {b: []};
+function f() {
+    let (a = [[] for (x in e)], {b: []} = x) {}
+}
+trap(f, 4, '');
+f();
+
+reportCompare(0, 0, 'ok');
--- a/js/src/tests/js1_8_5/regress/jstests.list
+++ b/js/src/tests/js1_8_5/regress/jstests.list
@@ -104,12 +104,13 @@ script regress-636364.js
 script regress-640075.js
 script regress-643222.js
 script regress-646820-1.js
 script regress-646820-2.js
 script regress-646820-3.js
 script regress-665355.js
 script regress-666599.js
 script regress-667047.js
+script regress-672892.js
 script regress-673070-1.js
 script regress-673070-2.js
 script regress-673070-3.js
 script regress-675581.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/regress/regress-672892.js
@@ -0,0 +1,8 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+with (0)
+    for (var b = 0 in 0)  // don't assert in parser
+	;
+
+reportCompare(0, 0, 'ok');
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -383,35 +383,28 @@ StackSpace::ensureEnoughSpaceToEnterTrac
     ptrdiff_t needed = TraceNativeStorage::MAX_NATIVE_STACK_SLOTS +
                        TraceNativeStorage::MAX_CALL_STACK_ENTRIES * VALUES_PER_STACK_FRAME;
     return ensureSpace(cx, DONT_REPORT_ERROR, firstUnused(), needed);
 }
 #endif
 
 STATIC_POSTCONDITION(!return || ubound(from) >= nvals)
 JS_ALWAYS_INLINE bool
-StackSpace::ensureSpace(JSContext *cx, MaybeReportError report, Value *from, ptrdiff_t nvals,
-                        JSCompartment *dest) const
+StackSpace::ensureSpace(JSContext *cx, MaybeReportError report, Value *from, ptrdiff_t nvals) const
 {
     assertInvariants();
     JS_ASSERT(from >= firstUnused());
 #ifdef XP_WIN
     JS_ASSERT(from <= commitEnd_);
 #endif
     if (JS_UNLIKELY(conservativeEnd_ - from < nvals))
-        return ensureSpaceSlow(cx, report, from, nvals, dest);
+        return ensureSpaceSlow(cx, report, from, nvals);
     return true;
 }
 
-bool
-StackSpace::ensureSpace(JSContext *cx, MaybeReportError report, Value *from, ptrdiff_t nvals) const
-{
-    return ensureSpace(cx, report, from, nvals, cx->compartment);
-}
-
 inline Value *
 StackSpace::getStackLimit(JSContext *cx, MaybeReportError report)
 {
     FrameRegs &regs = cx->regs();
     uintN nvals = regs.fp()->numSlots() + VALUES_PER_STACK_FRAME;
     return ensureSpace(cx, report, regs.sp, nvals)
            ? conservativeEnd_
            : NULL;
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -409,23 +409,23 @@ StackSpace::mark(JSTracer *trc)
             slotsEnd = (Value *)fp;
         }
         MarkStackRangeConservatively(trc, seg->slotsBegin(), slotsEnd);
         nextSegEnd = (Value *)seg;
     }
 }
 
 JS_FRIEND_API(bool)
-StackSpace::ensureSpaceSlow(JSContext *cx, MaybeReportError report, Value *from, ptrdiff_t nvals,
-                            JSCompartment *dest) const
+StackSpace::ensureSpaceSlow(JSContext *cx, MaybeReportError report,
+                            Value *from, ptrdiff_t nvals) const
 {
     assertInvariants();
 
-    JS_ASSERT_IF(dest, cx);
-    bool trusted = !dest || dest->principals == cx->runtime->trustedPrincipals();
+    bool trusted = !cx->compartment ||
+                   cx->compartment->principals == cx->runtime->trustedPrincipals();
     Value *end = trusted ? trustedEnd_ : defaultEnd_;
 
     /*
      * conservativeEnd_ must stay below defaultEnd_: if conservativeEnd_ were
      * to be bumped past defaultEnd_, untrusted JS would be able to consume the
      * buffer space at the end of the stack reserved for trusted JS.
      */
 
@@ -543,27 +543,27 @@ ContextStack::containsSlow(const StackFr
  * pushing a StackSegment. The 'pushedSeg' outparam indicates whether such a
  * segment was pushed (and hence whether the caller needs to call popSegment).
  *
  * Additionally, to minimize calls to ensureSpace, ensureOnTop ensures that
  * there is space for nvars slots on top of the stack.
  */
 Value *
 ContextStack::ensureOnTop(JSContext *cx, MaybeReportError report, uintN nvars,
-                          MaybeExtend extend, bool *pushedSeg, JSCompartment *dest)
+                          MaybeExtend extend, bool *pushedSeg)
 {
     Value *firstUnused = space().firstUnused();
 
     if (onTop() && extend) {
-        if (!space().ensureSpace(cx, report, firstUnused, nvars, dest))
+        if (!space().ensureSpace(cx, report, firstUnused, nvars))
             return NULL;
         return firstUnused;
     }
 
-    if (!space().ensureSpace(cx, report, firstUnused, VALUES_PER_STACK_SEGMENT + nvars, dest))
+    if (!space().ensureSpace(cx, report, firstUnused, VALUES_PER_STACK_SEGMENT + nvars))
         return NULL;
 
     FrameRegs *regs;
     CallArgsList *calls;
     if (seg_ && extend) {
         regs = seg_->maybeRegs();
         calls = seg_->maybeCalls();
     } else {
@@ -572,23 +572,16 @@ ContextStack::ensureOnTop(JSContext *cx,
     }
 
     seg_ = new(firstUnused) StackSegment(seg_, space().seg_, regs, calls);
     space().seg_ = seg_;
     *pushedSeg = true;
     return seg_->slotsBegin();
 }
 
-Value *
-ContextStack::ensureOnTop(JSContext *cx, MaybeReportError report, uintN nvars,
-                          MaybeExtend extend, bool *pushedSeg)
-{
-    return ensureOnTop(cx, report, nvars, extend, pushedSeg, cx->compartment);
-}
-
 void
 ContextStack::popSegment()
 {
     space().seg_ = seg_->prevInMemory();
     seg_ = seg_->prevInContext();
 
     if (!seg_)
         cx_->maybeMigrateVersionOverride();
@@ -698,30 +691,28 @@ ContextStack::pushExecuteFrame(JSContext
 
     efg->prevRegs_ = seg_->pushRegs(efg->regs_);
     JS_ASSERT(space().firstUnused() == efg->regs_.sp);
     efg->setPushed(*this);
     return true;
 }
 
 bool
-ContextStack::pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *dfg)
+ContextStack::pushDummyFrame(JSContext *cx, MaybeReportError report, JSObject &scopeChain,
+                             DummyFrameGuard *dfg)
 {
-    JSCompartment *dest = scopeChain.compartment();
-
     uintN nvars = VALUES_PER_STACK_FRAME;
-    Value *firstUnused = ensureOnTop(cx, REPORT_ERROR, nvars, CAN_EXTEND, &dfg->pushedSeg_, dest);
+    Value *firstUnused = ensureOnTop(cx, report, nvars, CAN_EXTEND, &dfg->pushedSeg_);
     if (!firstUnused)
         return NULL;
 
     StackFrame *fp = reinterpret_cast<StackFrame *>(firstUnused);
     fp->initDummyFrame(cx, scopeChain);
     dfg->regs_.initDummyFrame(*fp);
 
-    cx->compartment = dest;
     dfg->prevRegs_ = seg_->pushRegs(dfg->regs_);
     JS_ASSERT(space().firstUnused() == dfg->regs_.sp);
     dfg->setPushed(*this);
     return true;
 }
 
 void
 ContextStack::popFrame(const FrameGuard &fg)
@@ -794,21 +785,34 @@ ContextStack::popGeneratorFrame(const Ge
 
     /* ~FrameGuard/popFrame will finish the popping. */
     JS_ASSERT(ImplicitCast<const FrameGuard>(gfg).pushed());
 }
 
 bool
 ContextStack::saveFrameChain()
 {
-    JSCompartment *dest = NULL;
+    /*
+     * The StackSpace uses the context's current compartment to determine
+     * whether to allow access to the privileged end-of-stack buffer.
+     * However, we always want saveFrameChain to have access to this privileged
+     * buffer since it gets used to prepare calling trusted JS. To force this,
+     * we clear the current compartment (which is interpreted by ensureSpace as
+     * 'trusted') and either restore it on OOM or let resetCompartment()
+     * clobber it.
+     */
+    JSCompartment *original = cx_->compartment;
+    cx_->compartment = NULL;
 
     bool pushedSeg;
-    if (!ensureOnTop(cx_, REPORT_ERROR, 0, CANT_EXTEND, &pushedSeg, dest))
+    if (!ensureOnTop(cx_, DONT_REPORT_ERROR, 0, CANT_EXTEND, &pushedSeg)) {
+        cx_->compartment = original;
+        js_ReportOverRecursed(cx_);
         return false;
+    }
 
     JS_ASSERT(pushedSeg);
     JS_ASSERT(!hasfp());
     JS_ASSERT(onTop() && seg_->isEmpty());
 
     cx_->resetCompartment();
     return true;
 }
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -39,17 +39,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef Stack_h__
 #define Stack_h__
 
 #include "jsfun.h"
 
 struct JSContext;
-struct JSCompartment;
 
 namespace js {
 
 class StackFrame;
 class FrameRegs;
 class StackSegment;
 class StackSpace;
 class ContextStack;
@@ -1326,24 +1325,19 @@ class StackSpace
         JS_STATIC_ASSERT(CAPACITY_VALS % COMMIT_VALS == 0);
     }
 
     friend class AllFramesIter;
     friend class ContextStack;
     friend class StackFrame;
 
     inline bool ensureSpace(JSContext *cx, MaybeReportError report,
-                            Value *from, ptrdiff_t nvals,
-                            JSCompartment *dest) const;
-    inline bool ensureSpace(JSContext *cx, MaybeReportError report,
                             Value *from, ptrdiff_t nvals) const;
     JS_FRIEND_API(bool) ensureSpaceSlow(JSContext *cx, MaybeReportError report,
-                                        Value *from, ptrdiff_t nvals,
-                                        JSCompartment *dest) const;
-
+                                        Value *from, ptrdiff_t nvals) const;
     StackSegment &findContainingSegment(const StackFrame *target) const;
 
   public:
     StackSpace();
     bool init();
     ~StackSpace();
 
     /*
@@ -1422,19 +1416,16 @@ class ContextStack
 #else
     void assertSpaceInSync() const {}
 #endif
 
     /* Implementation details of push* public interface. */
     StackSegment *pushSegment(JSContext *cx);
     enum MaybeExtend { CAN_EXTEND = true, CANT_EXTEND = false };
     Value *ensureOnTop(JSContext *cx, MaybeReportError report, uintN nvars,
-                       MaybeExtend extend, bool *pushedSeg,
-                       JSCompartment *dest);
-    Value *ensureOnTop(JSContext *cx, MaybeReportError report, uintN nvars,
                        MaybeExtend extend, bool *pushedSeg);
 
     inline StackFrame *
     getCallFrame(JSContext *cx, MaybeReportError report, const CallArgs &args,
                  JSFunction *fun, JSScript *script, StackFrame::Flags *pflags) const;
 
     /* Make pop* functions private since only called by guard classes. */
     void popSegment();
@@ -1506,26 +1497,19 @@ class ContextStack
     /*
      * Called by SendToGenerator to resume a yielded generator. In addition to
      * pushing a frame onto the VM stack, this function copies over the
      * floating frame stored in 'gen'. When 'gfg' is destroyed, the destructor
      * will copy the frame back to the floating frame.
      */
     bool pushGeneratorFrame(JSContext *cx, JSGenerator *gen, GeneratorFrameGuard *gfg);
 
-    /*
-     * When changing the compartment of a cx, it is necessary to immediately
-     * change the scope chain to a global in the right compartment since any
-     * amount of general VM code can run before the first scripted frame is
-     * pushed (if at all). This is currently and hackily accomplished by
-     * pushing a "dummy frame" with the correct scope chain. On success, this
-     * function will change the compartment to 'scopeChain.compartment()' and
-     * push a dummy frame for 'scopeChain'. On failure, nothing is changed.
-     */
-    bool pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *dfg);
+    /* Pushes a "dummy" frame; should be removed one day. */
+    bool pushDummyFrame(JSContext *cx, MaybeReportError report, JSObject &scopeChain,
+                        DummyFrameGuard *dfg);
 
     /*
      * An "inline frame" may only be pushed from within the top, active
      * segment. This is the case for calls made inside mjit code and Interpret.
      * The 'stackLimit' overload updates 'stackLimit' if it changes.
      */
     bool pushInlineFrame(JSContext *cx, FrameRegs &regs, const CallArgs &args,
                          JSObject &callee, JSFunction *fun, JSScript *script,
--- a/js/src/vm/String-inl.h
+++ b/js/src/vm/String-inl.h
@@ -84,16 +84,31 @@ JSDependentString::new_(JSContext *cx, J
 
     JSDependentString *str = (JSDependentString *)js_NewGCString(cx);
     if (!str)
         return NULL;
     str->init(base, chars, length);
     return str;
 }
 
+inline js::PropertyName *
+JSFlatString::toPropertyName(JSContext *cx)
+{
+#ifdef DEBUG
+    uint32 dummy;
+    JS_ASSERT(!isElement(&dummy));
+#endif
+    if (isAtom())
+        return asAtom().asPropertyName();
+    JSAtom *atom = js_AtomizeString(cx, this);
+    if (!atom)
+        return NULL;
+    return atom->asPropertyName();
+}
+
 JS_ALWAYS_INLINE void
 JSFixedString::init(const jschar *chars, size_t length)
 {
     d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
     d.u1.chars = chars;
 }
 
 JS_ALWAYS_INLINE JSFixedString *
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -33,19 +33,22 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#include "mozilla/RangedPtr.h"
+
 #include "String.h"
 #include "String-inl.h"
 
+using namespace mozilla;
 using namespace js;
 
 bool
 JSString::isShort() const
 {
     bool is_short = arenaHeader()->getThingKind() == gc::FINALIZE_SHORT_STRING;
     JS_ASSERT_IF(is_short, isFlat());
     return is_short;
@@ -312,8 +315,57 @@ JSDependentString::undepend(JSContext *c
     d.u1.chars = s;
 
     return &this->asFixed();
 }
 
 JSStringFinalizeOp JSExternalString::str_finalizers[JSExternalString::TYPE_LIMIT] = {
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
+
+bool
+JSFlatString::isElement(uint32 *indexp) const
+{
+    const jschar *s = charsZ();
+    jschar ch = *s;
+
+    if (!JS7_ISDEC(ch))
+        return false;
+
+    size_t n = length();
+    if (n > UINT32_CHAR_BUFFER_LENGTH)
+        return false;
+
+    /*
+     * Make sure to account for the '\0' at the end of characters, dereferenced
+     * in the loop below.
+     */
+    RangedPtr<const jschar> cp(s, n + 1);
+    const RangedPtr<const jschar> end(s + n, s, n + 1);
+
+    uint32 index = JS7_UNDEC(*cp++);
+    uint32 oldIndex = 0;
+    uint32 c = 0;
+
+    if (index != 0) {
+        while (JS7_ISDEC(*cp)) {
+            oldIndex = index;
+            c = JS7_UNDEC(*cp);
+            index = 10 * index + c;
+            cp++;
+        }
+    }
+
+    /* It's not an element if there are characters after the number. */
+    if (cp != end)
+        return false;
+
+    /*
+     * Look out for "4294967296" and larger-number strings that fit in
+     * UINT32_CHAR_BUFFER_LENGTH: only unsigned 32-bit integers shall pass.
+     */
+    if (oldIndex < UINT32_MAX / 10 || (oldIndex == UINT32_MAX / 10 && c <= (UINT32_MAX % 10))) {
+        *indexp = index;
+        return true;
+    }
+
+    return false;
+}
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -38,25 +38,49 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef String_h_
 #define String_h_
 
 #include "jscell.h"
 
+class JSString;
 class JSDependentString;
 class JSExtensibleString;
 class JSExternalString;
 class JSLinearString;
 class JSFixedString;
 class JSStaticAtom;
 class JSRope;
 class JSAtom;
 
+namespace js {
+
+class PropertyName;
+
+/* The buffer length required to contain any unsigned 32-bit integer. */
+static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1;
+
+/* N.B. must correspond to boolean tagging behavior. */
+enum InternBehavior
+{
+    DoNotInternAtom = false,
+    InternAtom = true
+};
+
+} /* namespace js */
+
+/*
+ * Find or create the atom for a string. Return null on failure to allocate
+ * memory.
+ */
+extern JSAtom *
+js_AtomizeString(JSContext *cx, JSString *str, js::InternBehavior ib = js::DoNotInternAtom);
+
 /*
  * JavaScript strings
  *
  * Conceptually, a JS string is just an array of chars and a length. This array
  * of chars may or may not be null-terminated and, if it is, the null character
  * is not included in the length.
  *
  * To improve performance of common operations, the following optimizations are
@@ -469,16 +493,31 @@ class JSFlatString : public JSLinearStri
 
   public:
     JS_ALWAYS_INLINE
     const jschar *charsZ() const {
         JS_ASSERT(isFlat());
         return chars();
     }
 
+    /*
+     * Returns true if this string's characters store an unsigned 32-bit
+     * integer value, initializing *indexp to that value if so.  (Thus if
+     * calling isElement returns true, js::IndexToString(cx, *indexp) will be a
+     * string equal to this string.)
+     */
+    bool isElement(uint32 *indexp) const;
+
+    /*
+     * Returns a property name represented by this string, or null on failure.
+     * You must verify that this is not an element per isElement before calling
+     * this method.
+     */
+    inline js::PropertyName *toPropertyName(JSContext *cx);
+
     /* Only called by the GC for strings with the FINALIZE_STRING kind. */
 
     inline void finalize(JSRuntime *rt);
 };
 
 JS_STATIC_ASSERT(sizeof(JSFlatString) == sizeof(JSString));
 
 class JSExtensibleString : public JSFlatString
@@ -673,16 +712,19 @@ class JSAtom : public JSFixedString
     static JSStaticAtom &unitStatic(jschar c);
 
     /* May not return atom, returns null on (reported) failure. */
     static inline JSLinearString *getUnitStringForElement(JSContext *cx, JSString *str, size_t index);
 
     /* Return null if no static atom exists for the given (chars, length). */
     static inline JSStaticAtom *lookupStatic(const jschar *chars, size_t length);
 
+    /* Returns the PropertyName for this.  isElement() must be false. */
+    inline js::PropertyName *asPropertyName();
+
     inline void finalize(JSRuntime *rt);
 };
 
 JS_STATIC_ASSERT(sizeof(JSAtom) == sizeof(JSString));
 
 class JSInlineAtom : public JSInlineString /*, JSAtom */
 {
     /*
@@ -703,17 +745,31 @@ class JSShortAtom : public JSShortString
 
 JS_STATIC_ASSERT(sizeof(JSShortAtom) == sizeof(JSShortString));
 
 class JSStaticAtom : public JSAtom
 {};
 
 JS_STATIC_ASSERT(sizeof(JSStaticAtom) == sizeof(JSString));
 
-/* Avoid requring vm/String-inl.h just to call getChars. */
+namespace js {
+
+/*
+ * Represents an atomized string which does not contain an unsigned 32-bit
+ * value.  That is, it is never the case that for a PropertyName propname,
+ * ToString(ToUint32(propname)) is equal to propname.
+ */
+class PropertyName : public JSAtom
+{};
+
+JS_STATIC_ASSERT(sizeof(PropertyName) == sizeof(JSString));
+
+} /* namespace js */
+
+/* Avoid requiring vm/String-inl.h just to call getChars. */
 
 JS_ALWAYS_INLINE const jschar *
 JSString::getChars(JSContext *cx)
 {
     if (JSLinearString *str = ensureLinear(cx))
         return str->chars();
     return NULL;
 }
@@ -753,9 +809,19 @@ JSString::ensureFixed(JSContext *cx)
         JS_ASSERT((d.lengthAndFlags & FLAT_MASK) == 0);
         JS_STATIC_ASSERT(EXTENSIBLE_FLAGS == (JS_BIT(2) | JS_BIT(3)));
         JS_STATIC_ASSERT(FIXED_FLAGS == JS_BIT(2));
         d.lengthAndFlags ^= JS_BIT(3);
     }
     return &asFixed();
 }
 
+inline js::PropertyName *
+JSAtom::asPropertyName()
+{
+#ifdef DEBUG
+    uint32 dummy;
+    JS_ASSERT(!isElement(&dummy));
 #endif
+    return static_cast<js::PropertyName *>(this);
+}
+
+#endif
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1938,17 +1938,17 @@ InterpolateColor(const gfxRGBA& aC1, con
                  aC2.b*aFrac + aC1.b*other,
                  aC2.a*aFrac + aC1.a*other);
 }
 
 static nscoord
 FindTileStart(nscoord aDirtyCoord, nscoord aTilePos, nscoord aTileDim)
 {
   NS_ASSERTION(aTileDim > 0, "Non-positive tile dimension");
-  double multiples = NS_floor(double(aDirtyCoord - aTilePos)/aTileDim);
+  double multiples = floor(double(aDirtyCoord - aTilePos)/aTileDim);
   return NSToCoordRound(multiples*aTileDim + aTilePos);
 }
 
 void
 nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
                               nsRenderingContext& aRenderingContext,
                               nsStyleGradient* aGradient,
                               const nsRect& aDirtyRect,
@@ -2045,17 +2045,17 @@ nsCSSRendering::PaintGradient(nsPresCont
       // stop-offsets.
       double lastStop = stops[stops.Length() - 1].mPosition;
       double stopDelta = lastStop - firstStop;
       // If all the stops are in approximately the same place then logic below
       // will kick in that makes us draw just the last stop color, so don't
       // try to do anything in that case. We certainly need to avoid
       // dividing by zero.
       if (stopDelta >= 1e-6) {
-        double instanceCount = NS_ceil(-firstStop/stopDelta);
+        double instanceCount = ceil(-firstStop/stopDelta);
         // Advance stops by instanceCount multiples of the period of the
         // repeating gradient.
         double offset = instanceCount*stopDelta;
         for (PRUint32 i = 0; i < stops.Length(); i++) {
           stops[i].mPosition += offset;
         }
       }
     } else {
@@ -3602,25 +3602,25 @@ nsCSSRendering::GetTextDecorationRectInt
   NS_ASSERTION(aStyle <= NS_STYLE_TEXT_DECORATION_STYLE_WAVY,
                "Invalid aStyle value");
 
   if (aStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE)
     return gfxRect(0, 0, 0, 0);
 
   PRBool canLiftUnderline = aDescentLimit >= 0.0;
 
-  const gfxFloat left  = NS_floor(aPt.x + 0.5),
-                 right = NS_floor(aPt.x + aLineSize.width + 0.5);
+  const gfxFloat left  = floor(aPt.x + 0.5),
+                 right = floor(aPt.x + aLineSize.width + 0.5);
   gfxRect r(left, 0, right - left, 0);
 
   gfxFloat lineHeight = NS_round(aLineSize.height);
   lineHeight = NS_MAX(lineHeight, 1.0);
 
   gfxFloat ascent = NS_round(aAscent);
-  gfxFloat descentLimit = NS_floor(aDescentLimit);
+  gfxFloat descentLimit = floor(aDescentLimit);
 
   gfxFloat suggestedMaxRectHeight = NS_MAX(NS_MIN(ascent, descentLimit), 1.0);
   r.height = lineHeight;
   if (aStyle == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE) {
     /**
      *  We will draw double line as:
      *
      * +-------------------------------------------+
@@ -3666,17 +3666,17 @@ nsCSSRendering::GetTextDecorationRectInt
         // because the thickness has some meaning.  E.g., the 1px wavy line and
         // 2px wavy line can be used for different meaning in IME selections
         // at same time.
         r.height = NS_MAX(suggestedMaxRectHeight, lineHeight * 2.0);
       }
     }
   }
 
-  gfxFloat baseline = NS_floor(aPt.y + aAscent + 0.5);
+  gfxFloat baseline = floor(aPt.y + aAscent + 0.5);
   gfxFloat offset = 0.0;
   switch (aDecoration) {
     case NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE:
       offset = aOffset;
       if (canLiftUnderline) {
         if (descentLimit < -offset + r.Height()) {
           // If we can ignore the offset and the decoration line is overflowing,
           // we should align the bottom edge of the decoration line rect if it's
@@ -3687,25 +3687,25 @@ nsCSSRendering::GetTextDecorationRectInt
           offset = NS_MIN(offsetBottomAligned, offsetTopAligned);
         }
       }
       break;
     case NS_STYLE_TEXT_DECORATION_LINE_OVERLINE:
       offset = aOffset - lineHeight + r.Height();
       break;
     case NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH: {
-      gfxFloat extra = NS_floor(r.Height() / 2.0 + 0.5);
+      gfxFloat extra = floor(r.Height() / 2.0 + 0.5);
       extra = NS_MAX(extra, lineHeight);
       offset = aOffset - lineHeight + extra;
       break;
     }
     default:
       NS_ERROR("Invalid decoration value!");
   }
-  r.y = baseline - NS_floor(offset + 0.5);
+  r.y = baseline - floor(offset + 0.5);
   return r;
 }
 
 // ------------------
 // ImageRenderer
 // ------------------
 ImageRenderer::ImageRenderer(nsIFrame* aForFrame,
                              const nsStyleImage* aImage,
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -2761,17 +2761,17 @@ AdvanceToNextTab(gfxFloat aX, nsIFrame* 
 {
   if (*aCachedTabWidth < 0) {
     *aCachedTabWidth = ComputeTabWidthAppUnits(aFrame, aTextRun);
   }
 
   // Advance aX to the next multiple of *aCachedTabWidth. We must advance
   // by at least 1 appunit.
   // XXX should we make this 1 CSS pixel?
-  return NS_ceil((aX + 1)/(*aCachedTabWidth))*(*aCachedTabWidth);
+  return ceil((aX + 1)/(*aCachedTabWidth))*(*aCachedTabWidth);
 }
 
 void
 PropertyProvider::CalcTabWidths(PRUint32 aStart, PRUint32 aLength)
 {
   if (!mTabWidths) {
     if (mReflowing && !mLineContainer) {
       // Intrinsic width computation does its own tab processing. We
@@ -4512,17 +4512,17 @@ ComputeSelectionUnderlineHeight(nsPresCo
       // the default font size, we should use the actual font size because the
       // computed value from the default font size can be too thick for the
       // current font size.
       PRInt32 defaultFontSize =
         aPresContext->AppUnitsToDevPixels(nsStyleFont(aPresContext).mFont.size);
       gfxFloat fontSize = NS_MIN(gfxFloat(defaultFontSize),
                                  aFontMetrics.emHeight);
       fontSize = NS_MAX(fontSize, 1.0);
-      return NS_ceil(fontSize / 20);
+      return ceil(fontSize / 20);
     }
     default:
       NS_WARNING("Requested underline style is not valid");
       return aFontMetrics.underlineSize;
   }
 }
 
 /**
new file mode 100644
--- /dev/null
+++ b/layout/reftests/editor/338427-1-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <textarea spellcheck="false" lang="testing-XX">strangeimpossibleword</textarea>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/editor/338427-1.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <textarea lang="testing-XX">strangeimpossibleword</textarea>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/editor/338427-2-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+function init() {
+    var editor = document.getElementById('editor');
+    editor.addEventListener("focus", function() {
+        window.setTimeout(function() {
+            document.documentElement.className = '';
+        }, 0);
+    }, false);
+    editor.focus();
+}
+</script>
+<body onload="init()">
+    <div id="editor" lang="testing-XX" contenteditable="true" spellcheck="false">strangeimpossibleword</div>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/editor/338427-2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+function init() {
+    var editor = document.getElementById('editor');
+    editor.addEventListener("focus", function() {
+        window.setTimeout(function() {
+            document.documentElement.className = '';
+        }, 0);
+    }, false);
+    editor.focus();
+}
+</script>
+<body onload="init()">
+    <div id="editor" lang="testing-XX" contenteditable="true">strangeimpossibleword</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/editor/338427-3-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+function init() {
+    var editor = document.getElementById('editor');
+    editor.setAttribute('lang', 'testing-XX');
+    editor.addEventListener("focus", function() {
+        window.setTimeout(function() {
+            document.documentElement.className = '';
+        }, 0);
+    }, false);
+    editor.focus();
+}
+</script>
+<body onload="init()">
+    <textarea id="editor" spellcheck="false" lang="en-US">strangeimpossibleword</textarea>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/editor/338427-3.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+function init() {
+    var editor = document.getElementById('editor');
+    editor.setAttribute('lang', 'testing-XX');
+    editor.addEventListener("focus", function() {
+        window.setTimeout(function() {
+            document.documentElement.className = '';
+        }, 0);
+    }, false);
+    editor.focus();
+}
+</script>
+<body onload="init()">
+    <textarea id="editor" lang="en-US">strangeimpossibleword</textarea>
+</body>
+</html>
--- a/layout/reftests/editor/reftest.list
+++ b/layout/reftests/editor/reftest.list
@@ -59,8 +59,11 @@ fails-if(Android) != spellcheck-hyphen-m
 == unneeded_scroll.html unneeded_scroll-ref.html
 == caret_on_presshell_reinit.html caret_on_presshell_reinit-ref.html
 == caret_on_presshell_reinit-2.html caret_on_presshell_reinit-ref.html
 == 642800.html 642800-ref.html
 == selection_visibility_after_reframe.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-2.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-3.html selection_visibility_after_reframe-ref.html
 == 672709.html 672709-ref.html
+== 338427-1.html 338427-1-ref.html
+skip-if(Android) == 338427-2.html 338427-2-ref.html
+skip-if(Android) == 338427-3.html 338427-3-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/unicode/langattribute-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="dk">
+<head>
+    <title>testing lang attribute</title>
+    <style>
+    div[lang="fr"] {
+        color: green;
+    }
+    div[lang="de"] > input {
+        color: blue;
+    }
+    div:not([lang]) {
+        color: yellow;
+    }
+    </style>
+</head>
+<body>
+<div lang="fr">fr language</div>
+<div lang="de">
+    <input value="de language">
+</div>
+<div>
+    dk language
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/unicode/langattribute.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="dk">
+<head>
+    <title>testing lang attribute</title>
+    <style>
+    div:lang(fr) {
+        color: green;
+    }
+    input:lang(de) {
+        color: blue;
+    }
+    div:lang(dk) {
+        color: yellow;
+    }
+    </style>
+</head>
+<body>
+<div lang="fr">fr language</div>
+<div lang="de">
+    <input value="de language">
+</div>
+<div>
+    dk language
+</div>
+</body>
+</html>
--- a/layout/reftests/unicode/reftest.list
+++ b/layout/reftests/unicode/reftest.list
@@ -1,6 +1,7 @@
 == unicode-attribute-selector.html unicode-ref.html
 == unicode-element-selector.html unicode-ref.html
 == unicode-lang.html unicode-ref.html
 == unicode-media-query-media-type.html unicode-ref-print.html
 == unicode-media-query-query.html unicode-ref-print.html
 == unicode-pseudo-selector.html unicode-ref.html
+== langattribute.html langattribute-ref.html
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -1190,39 +1190,16 @@ nsCSSRuleProcessor::HasSystemMetric(nsIA
 nsCSSRuleProcessor::GetWindowsThemeIdentifier()
 {
   if (!sSystemMetrics)
     InitSystemMetrics();
   return sWinThemeId;
 }
 #endif
 
-// If we have a useful @lang, then aLang will end up nonempty.
-static void GetLang(nsIContent* aContent, nsString& aLang)
-{
-  for (nsIContent* content = aContent; content;
-       content = content->GetParent()) {
-    if (content->GetAttrCount() > 0) {
-      // xml:lang has precedence over lang on HTML elements (see
-      // XHTML1 section C.7).
-      PRBool hasAttr = content->GetAttr(kNameSpaceID_XML, nsGkAtoms::lang,
-                                        aLang);
-      if (!hasAttr && content->IsHTML()) {
-        hasAttr = content->GetAttr(kNameSpaceID_None, nsGkAtoms::lang,
-                                   aLang);
-      }
-      NS_ASSERTION(hasAttr || aLang.IsEmpty(),
-                   "GetAttr that returns false should not make string non-empty");
-      if (hasAttr) {
-        return;
-      }
-    }
-  }
-}
-
 /* static */
 nsEventStates
 nsCSSRuleProcessor::GetContentState(Element* aElement)
 {
   // FIXME: RequestLinkStateUpdate is a hack; see bug 660959.
   aElement->RequestLinkStateUpdate();
   nsEventStates state = aElement->State();
 
@@ -1692,17 +1669,17 @@ static PRBool SelectorMatches(Element* a
             return PR_FALSE;
           }
 
           // We have to determine the language of the current element.  Since
           // this is currently no property and since the language is inherited
           // from the parent we have to be prepared to look at all parent
           // nodes.  The language itself is encoded in the LANG attribute.
           nsAutoString language;
-          GetLang(aElement, language);
+          aElement->GetLang(language);
           if (!language.IsEmpty()) {
             if (!nsStyleUtil::DashMatchCompare(language,
                                                nsDependentString(pseudoClass->u.mString),
                                                nsASCIICaseInsensitiveStringComparator())) {
               return PR_FALSE;
             }
             // This pseudo-class matched; move on to the next thing
             break;
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -314,18 +314,18 @@ static nscoord CalcLengthWith(const nsCS
     case eCSSUnit_Char: {
       nsFont font = styleFont->mFont;
       font.size = aFontSize;
       nsRefPtr<nsFontMetrics> fm =
         aPresContext->GetMetricsFor(font, aUseUserFontSet);
       gfxFloat zeroWidth = (fm->GetThebesFontGroup()->GetFontAt(0)
                             ->GetMetrics().zeroOrAveCharWidth);
 
-      return ScaleCoord(aValue, NS_ceil(aPresContext->AppUnitsPerDevPixel() *
-                                        zeroWidth));
+      return ScaleCoord(aValue, ceil(aPresContext->AppUnitsPerDevPixel() *
+                                     zeroWidth));
     }
     // For properties for which lengths are the *only* units accepted in
     // calc(), we can handle calc() here and just compute a final
     // result.  We ensure that we don't get to this code for other
     // properties by not calling CalcLength in those cases:  SetCoord
     // only calls CalcLength for a calc when it is appropriate to do so.
     case eCSSUnit_Calc:
     case eCSSUnit_Calc_Plus:
--- a/layout/style/nsStyleAnimation.cpp
+++ b/layout/style/nsStyleAnimation.cpp
@@ -1379,18 +1379,18 @@ nsStyleAnimation::AddWeighted(nsCSSPrope
     case eUnit_Normal:
     case eUnit_UnparsedString:
       return PR_FALSE;
 
     case eUnit_Enumerated:
       switch (aProperty) {
         case eCSSProperty_font_stretch: {
           // Animate just like eUnit_Integer.
-          PRInt32 result = NS_floor(aCoeff1 * double(aValue1.GetIntValue()) +
-                                    aCoeff2 * double(aValue2.GetIntValue()));
+          PRInt32 result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
+                                 aCoeff2 * double(aValue2.GetIntValue()));
           if (result < NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED) {
             result = NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED;
           } else if (result > NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED) {
             result = NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED;
           }
           aResultValue.SetIntValue(result, eUnit_Enumerated);
           return PR_TRUE;
         }
@@ -1404,18 +1404,18 @@ nsStyleAnimation::AddWeighted(nsCSSPrope
       PRInt32 result = interp > 0.0 ? NS_STYLE_VISIBILITY_VISIBLE
                                     : NS_STYLE_VISIBILITY_HIDDEN;
       aResultValue.SetIntValue(result, eUnit_Visibility);
       return PR_TRUE;
     }
     case eUnit_Integer: {
       // http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types-
       // says we should use floor
-      PRInt32 result = NS_floor(aCoeff1 * double(aValue1.GetIntValue()) +
-                                aCoeff2 * double(aValue2.GetIntValue()));
+      PRInt32 result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
+                             aCoeff2 * double(aValue2.GetIntValue()));
       if (aProperty == eCSSProperty_font_weight) {
         if (result < 100) {
           result = 100;
         } else if (result > 900) {
           result = 900;
         }
         result -= result % 100;
       } else {
--- a/mobile/chrome/content/ContextCommands.js
+++ b/mobile/chrome/content/ContextCommands.js
@@ -24,16 +24,23 @@ var ContextCommands = {
       let json = {x: x, y: y, command: "paste" };
       messageManager.sendAsyncMessage("Browser:ContextCommand", json);
     } else {
       target.editor.paste(Ci.nsIClipboard.kGlobalClipboard);
       target.focus();
     }
   },
 
+  pasteAndGo: function cc_pasteAndGo() {
+    let target = ContextHelper.popupState.target;
+    target.editor.selectAll();
+    target.editor.paste(Ci.nsIClipboard.kGlobalClipboard);
+    BrowserUI.goToURI();
+  },
+
   selectAll: function cc_selectAll() {
     let target = ContextHelper.popupState.target;
     if (target.localName == "browser") {
       let x = ContextHelper.popupState.x;
       let y = ContextHelper.popupState.y;
       let json = {x: x, y: y, command: "select-all" };
       messageManager.sendAsyncMessage("Browser:ContextCommand", json);
     } else {
--- a/mobile/chrome/content/bindings.xml
+++ b/mobile/chrome/content/bindings.xml
@@ -1815,17 +1815,21 @@
 
           if (selectionStart > 0 || selectionEnd < aTextbox.textLength)
             json.types.push("select-all");
 
           let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
           let flavors = ["text/unicode"];
           let hasData = clipboard.hasDataMatchingFlavors(flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard);
 
-          if (hasData && (!aTextbox.readOnly || aIgnoreReadOnly))
+          if (hasData && (!aTextbox.readOnly || aIgnoreReadOnly)) {
             json.types.push("paste");
+            if (aTextbox.type == "url") {
+              json.types.push("paste-url");
+            }
+          }
 
           ContextHelper.showPopup({ target: aTextbox, json: json });
         ]]></body>
       </method>
     </implementation>
   </binding>
 </bindings>
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -376,16 +376,17 @@ var Browser = {
     messageManager.addMessageListener("Browser:CanCaptureMouse:Return", this);
     messageManager.addMessageListener("Browser:FormSubmit", this);
     messageManager.addMessageListener("Browser:KeyPress", this);
     messageManager.addMessageListener("Browser:ZoomToPoint:Return", this);
     messageManager.addMessageListener("Browser:CanUnload:Return", this);
     messageManager.addMessageListener("scroll", this);
     messageManager.addMessageListener("Browser:CertException", this);
     messageManager.addMessageListener("Browser:BlockedSite", this);
+    messageManager.addMessageListener("Browser:ErrorPage", this);
 
     // Broadcast a UIReady message so add-ons know we are finished with startup
     let event = document.createEvent("Events");
     event.initEvent("UIReady", true, false);
     window.dispatchEvent(event);
 
     // If we have an opener this was not the first window opened and will not
     // receive an initial resize event. instead we fire the resize handler manually
@@ -478,16 +479,17 @@ var Browser = {
 
     messageManager.removeMessageListener("Browser:ViewportMetadata", this);
     messageManager.removeMessageListener("Browser:FormSubmit", this);
     messageManager.removeMessageListener("Browser:KeyPress", this);
     messageManager.removeMessageListener("Browser:ZoomToPoint:Return", this);
     messageManager.removeMessageListener("scroll", this);
     messageManager.removeMessageListener("Browser:CertException", this);
     messageManager.removeMessageListener("Browser:BlockedSite", this);
+    messageManager.removeMessageListener("Browser:ErrorPage", this);
 
     var os = Services.obs;
     os.removeObserver(XPInstallObserver, "addon-install-blocked");
     os.removeObserver(XPInstallObserver, "addon-install-started");
     os.removeObserver(SessionHistoryObserver, "browser:purge-session-history");
     os.removeObserver(ContentCrashObserver, "ipc:content-shutdown");
     os.removeObserver(MemoryObserver, "memory-pressure");
 
@@ -931,16 +933,24 @@ var Browser = {
           Cu.reportError("Couldn't get phishing info URL: " + e);
         }
         break;
       }
     }
   },
 
   /**
+   * Handle error page message from the content.
+   */
+  _handleErrorPage: function _handleErrorPage(aMessage) {
+    let tab = this.getTabForBrowser(aMessage.target);
+    tab.updateThumbnail({ force: true });
+  },
+
+  /**
    * Compute the sidebar percentage visibility.
    *
    * @param [optional] dx
    * @param [optional] dy an offset distance at which to perform the visibility
    * computation
    */
   computeSidebarVisibility: function computeSidebarVisibility(dx, dy) {
     function visibility(aSidebarRect, aVisibleRect) {
@@ -1220,16 +1230,19 @@ var Browser = {
         }
         break;
       case "Browser:CertException":
         this._handleCertException(aMessage);
         break;
       case "Browser:BlockedSite":
         this._handleBlockedSite(aMessage);
         break;
+      case "Browser:ErrorPage":
+        this._handleErrorPage(aMessage);
+        break;
     }
   }
 };
 
 
 Browser.MainDragger = function MainDragger() {
   this._horizontalScrollbar = document.getElementById("horizontal-scroller");
   this._verticalScrollbar = document.getElementById("vertical-scroller");
@@ -2966,27 +2979,30 @@ Tab.prototype = {
 
     return this._browser.getBoundingClientRect().width / browserW;
   },
 
   get allowZoom() {
     return this.metadata.allowZoom && !Util.isURLEmpty(this.browser.currentURI.spec);
   },
 
-  updateThumbnail: function updateThumbnail() {
+  updateThumbnail: function updateThumbnail(options) {
+    let options = options || {};
     let browser = this._browser;
 
     if (this._loading) {
       this._drawThumb = true;
       return;
     }
 
+    let forceUpdate = ("force" in options && options.force);
+
     // Do not repaint thumbnail if we already painted for this load. Bad things
     // happen when we do async canvas draws in quick succession.
-    if (!browser || this._thumbnailWindowId == browser.contentWindowId)
+    if (!forceUpdate && (!browser || this._thumbnailWindowId == browser.contentWindowId))
       return;
 
     // Do not try to paint thumbnails if contentWindowWidth/Height have not been
     // set yet. This also blows up for async canvas draws.
     if (!browser.contentWindowWidth || !browser.contentWindowHeight)
       return;
 
     this._thumbnailWindowId = browser.contentWindowId;
--- a/mobile/chrome/content/browser.xul
+++ b/mobile/chrome/content/browser.xul
@@ -621,16 +621,19 @@
             <label value="&copy.label;"/>
           </richlistitem>
           <richlistitem class="context-command" id="context-copy-all" type="copy-all" onclick="ContextCommands.copy();">
             <label value="&copyAll.label;"/>
           </richlistitem>
           <richlistitem class="context-command" id="context-paste" type="paste" onclick="ContextCommands.paste();">
             <label value="&paste.label;"/>
           </richlistitem>
+          <richlistitem class="context-command" id="context-paste-n-go" type="paste-url" onclick="ContextCommands.pasteAndGo();">
+            <label value="&pasteAndGo.label;"/>
+          </richlistitem>
           <richlistitem class="context-command" id="context-select-all" type="select-all" onclick="ContextCommands.selectAll();">
             <label value="&selectAll.label;"/>
           </richlistitem>
           <richlistitem class="context-command" id="context-openinnewtab" type="link-openable" onclick="ContextCommands.openInNewTab();">
             <label value="&contextOpenInNewTab.label;"/>
           </richlistitem>
           <richlistitem class="context-command" id="context-bookmark-link" type="link" onclick="ContextCommands.bookmarkLink();">
             <label value="&contextBookmarkLink.label;"/>
--- a/mobile/chrome/content/content.js
+++ b/mobile/chrome/content/content.js
@@ -274,16 +274,17 @@ let Content = {
     addMessageListener("Browser:ContextCommand", this);
     addMessageListener("Browser:CanUnload", this);
     addMessageListener("Browser:CanCaptureMouse", this);
 
     if (Util.isParentProcess())
       addEventListener("DOMActivate", this, true);
 
     addEventListener("MozApplicationManifest", this, false);
+    addEventListener("DOMContentLoaded", this, false);
     addEventListener("pagehide", this, false);
     addEventListener("keypress", this, false, false);
 
     // Attach a listener to watch for "click" events bubbling up from error
     // pages and other similar page. This lets us fix bugs like 401575 which
     // require error page UI to do privileged things, without letting error
     // pages have any privilege themselves.
     addEventListener("click", this, false);
@@ -379,16 +380,20 @@ let Content = {
             // TODO: We'll need to impl notifications in the parent process and use the preference code found here:
             //       http://hg.mozilla.org/mozilla-central/file/855e5cd3c884/browser/base/content/browser.js#l2672
             //       http://hg.mozilla.org/mozilla-central/file/855e5cd3c884/browser/components/safebrowsing/content/globalstore.js
           }
         }
         break;
       }
 
+      case "DOMContentLoaded":
+        this._maybeNotifyErroPage();
+        break;
+
       case "pagehide":
         if (aEvent.target == content.document)
           this._resetFontSize();          
         break;
     }
   },
 
   receiveMessage: function receiveMessage(aMessage) {
@@ -597,16 +602,24 @@ let Content = {
         sendAsyncMessage("Browser:CanCaptureMouse:Return", {
           contentMightCaptureMouse: content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).mayHaveTouchEventListeners
         });
         break;
       }
     }
   },
 
+  _maybeNotifyErroPage: function _maybeNotifyErroPage() {
+    // Notify browser that an error page is being shown instead
+    // of the target location. Necessary to get proper thumbnail
+    // updates on chrome for error pages.
+    if (content.location.href !== content.document.documentURI)
+      sendAsyncMessage("Browser:ErrorPage", null);
+  },
+
   _resetFontSize: function _resetFontSize() {
     this._isZoomedToElement = false;
     this._setMinFontSize(0);
   },
 
   _highlightElement: null,
 
   _doTapHighlight: function _doTapHighlight(aElement) {
--- a/mobile/chrome/content/preferences.js
+++ b/mobile/chrome/content/preferences.js
@@ -250,16 +250,21 @@ var PreferencesView = {
         let currentURL = Browser.selectedBrowser.currentURI.spec;
         if (currentURL == "about:home") {
           value = "default";
         } else {
           url = currentURL;
           display = Browser.selectedBrowser.contentTitle || currentURL;
         }
         break;
+      case "custom":
+        // If value is custom, this means the user is trying to
+        // set homepage to the same custom value. Do nothing in
+        // this case.
+        return;
     }
 
     // Show or hide the title or URL of the custom homepage
     this._showHomePageHint(display);
 
     // Is the helper already in the list
     let helper = null;
     let items = options.menupopup.getElementsByAttribute("value", "custom");
--- a/mobile/installer/Makefile.in
+++ b/mobile/installer/Makefile.in
@@ -178,16 +178,24 @@ PP_DEB_FILES =	debian/control \
 		debian/fennec.prerm \
 		debian/fennec.postinst \
 		$(NULL)
 
 ifdef MOZ_ENABLE_CONTENTMANAGER
 PP_DEB_FILES += debian/fennec.aegis \
                $(NULL)
 endif
+ifeq ($(MOZ_PLATFORM_MAEMO),6)
+PP_DEB_FILES += debian/backup \
+                debian/restore \
+		 debian/fennec.conf \
+		 debian/fennec-cud.sh \
+		 debian/fennec-rfs.sh \
+                $(NULL)
+endif
 
 $(PP_DEB_FILES):
 	@$(EXIT_ON_ERROR) \
 	for f in $(PP_DEB_FILES); do \
            src=$(srcdir)/debian/`basename $$f`.in; \
 	   echo $$src ">" $$f ;\
            $(RM) -f $$f; \
            mkdir -p debian;  \
@@ -202,16 +210,26 @@ deb: $(PP_DEB_FILES) $(DIST)/branding/$(
 	$(NSINSTALL) -D $(DEBDESTDIR)/$(installdir)
 	cp -pRL $(DIST)/$(MOZ_APP_NAME)/* $(DEBDESTDIR)/$(installdir)
 ifeq ($(MOZ_PLATFORM_MAEMO),6)
 	$(NSINSTALL)  debian/$(MOZ_APP_NAME).desktop $(DEBDESTDIR)/usr/share/applications/
 	$(NSINSTALL) -D $(DEBDESTDIR)/usr/share/dbus-1/services/
 	cp debian/$(MOZ_APP_NAME).service $(DEBDESTDIR)/usr/share/dbus-1/services/org.mozilla.$(MOZ_APP_NAME).service
 	$(NSINSTALL) -D $(DEBDESTDIR)/usr/share/themes/blanco/meegotouch/icons/
 	cp $(DIST)/branding/$(MOZ_APP_NAME)_scalable.png $(DEBDESTDIR)/usr/share/themes/blanco/meegotouch/icons/$(MOZ_APP_NAME).png
+	$(NSINSTALL) -D $(DEBDESTDIR)/usr/share/backup-framework/applications
+	$(NSINSTALL) -D $(DEBDESTDIR)/usr/share/$(MOZ_APP_NAME)
+	$(NSINSTALL) -D $(DEBDESTDIR)/etc/osso-cud-scripts
+	$(NSINSTALL) -D $(DEBDESTDIR)/etc/osso-rfs-scripts
+	$(NSINSTALL) -m 755 debian/backup  $(DEBDESTDIR)/usr/share/$(MOZ_APP_NAME)/
+	$(NSINSTALL) -m 755 debian/restore $(DEBDESTDIR)/usr/share/$(MOZ_APP_NAME)/
+	cp debian/$(MOZ_APP_NAME).conf $(DEBDESTDIR)/usr/share/backup-framework/applications/$(MOZ_APP_NAME).conf
+	cp debian/$(MOZ_APP_NAME)-cud.sh $(DEBDESTDIR)/etc/osso-cud-scripts/$(MOZ_APP_NAME)-cud.sh
+	cp debian/$(MOZ_APP_NAME)-rfs.sh $(DEBDESTDIR)/etc/osso-rfs-scripts/$(MOZ_APP_NAME)-rfs.sh
+
 else
 	$(NSINSTALL)  debian/$(MOZ_APP_NAME).desktop $(DEBDESTDIR)/usr/share/applications/hildon/
 	$(NSINSTALL) -D $(DEBDESTDIR)/usr/share/dbus-1/services/
 	cp debian/$(MOZ_APP_NAME).service $(DEBDESTDIR)/usr/share/dbus-1/services/org.mozilla.$(MOZ_APP_NAME).service
 	$(NSINSTALL) -D $(DEBDESTDIR)/usr/share/icons/hicolor/scalable/hildon/
 	cp $(DIST)/branding/$(MOZ_APP_NAME)_scalable.png $(DEBDESTDIR)/usr/share/icons/hicolor/scalable/hildon/$(MOZ_APP_NAME).png
 	$(NSINSTALL) -D $(DEBDESTDIR)/usr/share/icons/hicolor/26x26/hildon/
 	cp $(DIST)/branding/$(MOZ_APP_NAME)_26x26.png $(DEBDESTDIR)/usr/share/icons/hicolor/26x26/hildon/$(MOZ_APP_NAME).png
new file mode 100644
--- /dev/null
+++ b/mobile/installer/debian/backup.in
@@ -0,0 +1,20 @@
+#filter substitution
+#!/bin/sh
+
+# We do not care about parameters yet
+
+FENNEC_HOME=$HOME/.mozilla/@MOZ_APP_NAME@
+BACKUP=$HOME/.mozilla/backup
+
+rm -rf $BACKUP || exit 2
+
+# do the backup only if there already is a profile
+if [ -d $FENNEC_HOME ]; then
+    cp -a $FENNEC_HOME $BACKUP || exit 2
+    find $BACKUP -name "*.dat" \
+          -o -name "*.mfasl" \
+          -o -name "Cache" \
+          -o -name "OfflineCache" | xargs rm -rf || exit 2
+fi
+  
+exit 0
new file mode 100644
--- /dev/null
+++ b/mobile/installer/debian/fennec-cud.sh.in
@@ -0,0 +1,3 @@
+#filter substitution
+#!/bin/sh
+rm -rf $HOME/.mozilla/@MOZ_APP_NAME@
new file mode 100644
--- /dev/null
+++ b/mobile/installer/debian/fennec-rfs.sh.in
@@ -0,0 +1,4 @@
+#filter substitution
+#!/bin/sh
+rm -rf $HOME/.mozilla/@MOZ_APP_NAME@
+gconftool-2 --recursive-unset /apps/@MOZ_APP_NAME@
new file mode 100644
--- /dev/null
+++ b/mobile/installer/debian/fennec.conf.in
@@ -0,0 +1,21 @@
+#filter substitution
+<backup-configuration>
+    <application-type>nokia</application-type>
+    <application-name>@MOZ_APP_NAME@</application-name>
+    <backup-method>backup-scripts</backup-method>
+
+    <backup-scripts>
+        <backup-script-name>
+        /usr/share/@MOZ_APP_NAME@/backup
+        </backup-script-name>
+        <restore-script-name>
+        /usr/share/@MOZ_APP_NAME@/restore
+        </restore-script-name>
+    </backup-scripts>
+
+    <locations>
+        <location type="file" category="settings">
+        $HOME/.mozilla/backup
+        </location>
+    </locations>
+</backup-configuration>
new file mode 100644
--- /dev/null
+++ b/mobile/installer/debian/restore.in
@@ -0,0 +1,15 @@
+#filter substitution
+#!/bin/sh
+
+# We do not care about parameters yet
+
+FENNEC_HOME=$HOME/.mozilla/@MOZ_APP_NAME@
+BACKUP=$HOME/.mozilla/backup
+
+rm -rf $FENNEC_HOME || exit 2
+
+# Fennec profile
+cp -a $BACKUP $FENNEC_HOME || exit 2
+
+exit 0
+
--- a/mobile/locales/en-US/chrome/browser.dtd
+++ b/mobile/locales/en-US/chrome/browser.dtd
@@ -11,16 +11,17 @@
 <!ENTITY newtab.label          "New Tab">
 <!ENTITY closetab.label        "Close Tab">
 
 <!ENTITY cut.label             "Cut">
 <!ENTITY copy.label            "Copy">
 <!ENTITY copyAll.label         "Copy All">
 <!ENTITY copylink.label        "Copy Link Location">
 <!ENTITY paste.label           "Paste">
+<!ENTITY pasteAndGo.label      "Paste &amp; Go">
 <!ENTITY delete.label          "Delete">
 <!ENTITY selectAll.label       "Select All">
 <!ENTITY noSuggestions.label   "(No suggestions)">
 <!ENTITY addToDictionary.label "Add to Dictionary">
 <!ENTITY inputMethod.label     "Select Input Method">
 
 <!ENTITY allPagesHeader.label      "All Pages">
 <!ENTITY bookmarksHeader.label     "Bookmarks">
--- a/services/sync/services-sync.js
+++ b/services/sync/services-sync.js
@@ -4,17 +4,17 @@ pref("services.sync.miscURL", "misc/");
 pref("services.sync.termsURL", "https://services.mozilla.com/tos/");
 pref("services.sync.privacyURL", "https://services.mozilla.com/privacy-policy/");
 pref("services.sync.statusURL", "https://services.mozilla.com/status/");
 pref("services.sync.syncKeyHelpURL", "https://services.mozilla.com/help/synckey");
 
 pref("services.sync.lastversion", "firstrun");
 pref("services.sync.sendVersionInfo", true);
 
-pref("services.sync.scheduler.singleDeviceInterval", 86400); // 1 day
+pref("services.sync.scheduler.singleDeviceInterval", 3600);  // 1 hour
 pref("services.sync.scheduler.idleInterval",         3600);  // 1 hour
 pref("services.sync.scheduler.activeInterval",       300);   // 5 minutes
 pref("services.sync.scheduler.immediateInterval",    60);    // 1 minute
 pref("services.sync.scheduler.idleTime",             300);   // 5 minutes
 
 pref("services.sync.engine.bookmarks", true);
 pref("services.sync.engine.history", true);
 pref("services.sync.engine.passwords", true);
--- a/toolkit/components/places/SQLFunctions.cpp
+++ b/toolkit/components/places/SQLFunctions.cpp
@@ -585,19 +585,19 @@ namespace places {
         if (!pointsForSampledVisits) {
           // For URIs with zero points in the sampled recent visits
           // but "browsing" type visits outside the sampling range, set
           // frecency to -visit_count, so they're still shown in autocomplete.
           NS_ADDREF(*_result = new IntegerVariant(-visitCount));
         }
         else {
           // Estimate frecency using the last few visits.
-          // Use NS_ceilf() so that we don't round down to 0, which
+          // Use ceilf() so that we don't round down to 0, which
           // would cause us to completely ignore the place during autocomplete.
-          NS_ADDREF(*_result = new IntegerVariant((PRInt32) NS_ceilf(fullVisitCount * NS_ceilf(pointsForSampledVisits) / numSampledVisits)));
+          NS_ADDREF(*_result = new IntegerVariant((PRInt32) ceilf(fullVisitCount * ceilf(pointsForSampledVisits) / numSampledVisits)));
         }
 
         return NS_OK;
       }
     }
 
     // This page is unknown or has no visits.  It could have just been added, so
     // use passed in or default values.
@@ -620,19 +620,19 @@ namespace places {
 
     if (typed) {
       bonus += history->GetFrecencyTransitionBonus(nsINavHistoryService::TRANSITION_TYPED, false);
     }
 
     // Assume "now" as our ageInDays, so use the first bucket.
     pointsForSampledVisits = history->GetFrecencyBucketWeight(1) * (bonus / (float)100.0); 
 
-    // use NS_ceilf() so that we don't round down to 0, which
+    // use ceilf() so that we don't round down to 0, which
     // would cause us to completely ignore the place during autocomplete
-    NS_ADDREF(*_result = new IntegerVariant((PRInt32) NS_ceilf(fullVisitCount * NS_ceilf(pointsForSampledVisits))));
+    NS_ADDREF(*_result = new IntegerVariant((PRInt32) ceilf(fullVisitCount * ceilf(pointsForSampledVisits))));
 
     return NS_OK;
   }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// GUID Creation Function
 
   //////////////////////////////////////////////////////////////////////////////
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -172,17 +172,17 @@ static const PRInt64 USECS_PER_DAY = LL_
 
 // These macros are used when splitting history by date.
 // These are the day containers and catch-all final container.
 #define HISTORY_ADDITIONAL_DATE_CONT_NUM 3
 // We use a guess of the number of months considering all of them 30 days
 // long, but we split only the last 6 months.
 #define HISTORY_DATE_CONT_NUM(_daysFromOldestVisit) \
   (HISTORY_ADDITIONAL_DATE_CONT_NUM + \
-   NS_MIN(6, (PRInt32)NS_ceilf((float)_daysFromOldestVisit/30)))
+   NS_MIN(6, (PRInt32)ceilf((float)_daysFromOldestVisit/30)))
 // Max number of containers, used to initialize the params hash.
 #define HISTORY_DATE_CONT_MAX 10
 
 // Initial size of the embed visits cache.
 #define EMBED_VISITS_INITIAL_CACHE_SIZE 128
 
 // Initial size of the recent events caches.
 #define RECENT_EVENTS_INITIAL_CACHE_SIZE 128
--- a/toolkit/content/InlineSpellChecker.jsm
+++ b/toolkit/content/InlineSpellChecker.jsm
@@ -126,18 +126,22 @@ InlineSpellChecker.prototype = {
   // this prepends up to "maxNumber" suggestions at the given menu position
   // for the word under the cursor. Returns the number of suggestions inserted.
   addSuggestionsToMenu: function(menu, insertBefore, maxNumber)
   {
     if (! this.mInlineSpellChecker || ! this.mOverMisspelling)
       return 0; // nothing to do
 
     var spellchecker = this.mInlineSpellChecker.spellChecker;
-    if (! spellchecker.CheckCurrentWord(this.mMisspelling))
-      return 0;  // word seems not misspelled after all (?)
+    try {
+      if (! spellchecker.CheckCurrentWord(this.mMisspelling))
+        return 0;  // word seems not misspelled after all (?)
+    } catch(e) {
+        return 0;
+    }
 
     this.mMenu = menu;
     this.mSpellSuggestions = [];
     this.mSuggestionItems = [];
     for (var i = 0; i < maxNumber; i ++) {
       var suggestion = spellchecker.GetSuggestedWord();
       if (! suggestion.length)
         break;
@@ -187,17 +191,20 @@ InlineSpellChecker.prototype = {
 
     if (! this.mInlineSpellChecker || ! this.enabled)
       return 0;
     var spellchecker = this.mInlineSpellChecker.spellChecker;
     var o1 = {}, o2 = {};
     spellchecker.GetDictionaryList(o1, o2);
     var list = o1.value;
     var listcount = o2.value;
-    var curlang = spellchecker.GetCurrentDictionary();
+    var curlang = "";
+    try {
+        curlang = spellchecker.GetCurrentDictionary();
+    } catch(e) {}
     var isoStrArray;
 
     for (var i = 0; i < list.length; i ++) {
       // get the display name for this dictionary
       isoStrArray = list[i].split(/[-_]/);
       var displayName = "";
       if (gLanguageBundle && isoStrArray[0]) {
         try {
--- a/toolkit/toolkit-makefiles.sh
+++ b/toolkit/toolkit-makefiles.sh
@@ -44,17 +44,16 @@ MAKEFILES_db="
 "
 
 MAKEFILES_dom="
   ipc/Makefile
   ipc/chromium/Makefile
   ipc/glue/Makefile
   ipc/ipdl/Makefile
   dom/Makefile
-  dom/public/coreEvents/Makefile
   dom/interfaces/base/Makefile
   dom/interfaces/canvas/Makefile
   dom/interfaces/core/Makefile
   dom/interfaces/css/Makefile
   dom/interfaces/events/Makefile
   dom/interfaces/geolocation/Makefile
   dom/interfaces/html/Makefile
   dom/interfaces/json/Makefile
--- a/widget/src/android/nsWindow.cpp
+++ b/widget/src/android/nsWindow.cpp
@@ -657,17 +657,18 @@ nsWindow::MakeFullScreen(PRBool aFullScr
 
 NS_IMETHODIMP
 nsWindow::SetWindowClass(const nsAString& xulWinType)
 {
     return NS_OK;
 }
 
 mozilla::layers::LayerManager*
-nsWindow::GetLayerManager(LayerManagerPersistence, bool* aAllowRetaining)
+nsWindow::GetLayerManager(PLayersChild*, LayersBackend, LayerManagerPersistence, 
+                          bool* aAllowRetaining)
 {
     if (aAllowRetaining) {
         *aAllowRetaining = true;
     }
     if (mLayerManager) {
         return mLayerManager;
     }
 
--- a/widget/src/android/nsWindow.h
+++ b/widget/src/android/nsWindow.h
@@ -158,18 +158,20 @@ public:
     NS_IMETHOD GetInputMode(IMEContext& aContext);
     NS_IMETHOD CancelIMEComposition();
 
     NS_IMETHOD OnIMEFocusChange(PRBool aFocus);
     NS_IMETHOD OnIMETextChange(PRUint32 aStart, PRUint32 aOldEnd, PRUint32 aNewEnd);
     NS_IMETHOD OnIMESelectionChange(void);
     virtual nsIMEUpdatePreference GetIMEUpdatePreference();
 
-    LayerManager* GetLayerManager(LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
-                                  bool* aAllowRetaining = nsnull);
+    LayerManager* GetLayerManager (PLayersChild* aShadowManager = nsnull, 
+                                   LayersBackend aBackendHint = LayerManager::LAYERS_NONE, 
+                                   LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT, 
+                                   bool* aAllowRetaining = nsnull);
     gfxASurface* GetThebesSurface();
 
     NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
 protected:
     void BringToFront();
     nsWindow *FindTopLevel();
     PRBool DrawTo(gfxASurface *targetSurface);
     PRBool IsTopLevel();
--- a/widget/src/cocoa/nsCocoaWindow.mm
+++ b/widget/src/cocoa/nsCocoaWindow.mm
@@ -2412,21 +2412,24 @@ DrawNativeTitlebar(CGContextRef aContext
             @"kCUIWidgetWindowFrame", @"widget",
             @"regularwin", @"windowtype",
             (aIsMain ? @"normal" : @"inactive"), @"state",
             [NSNumber numberWithInt:unifiedHeight], @"kCUIWindowFrameUnifiedTitleBarHeightKey",
             [NSNumber numberWithBool:YES], @"kCUIWindowFrameDrawTitleSeparatorKey",
             nil],
           nil);
 
-  // At some window widths the call to CUIDraw doesn't draw the top pixel strip.
-  // We don't want to have a flickering transparent line, so we overdraw it.
-  CGContextSetRGBFillColor(aContext, 0.95, 0.95, 0.95, 1);
-  CGContextFillRect(aContext, CGRectMake(0, CGRectGetMaxY(aTitlebarRect) - 1,
-                                         aTitlebarRect.size.width, 1));
+  if (nsToolkit::OnLionOrLater()) {
+    // On Lion the call to CUIDraw doesn't draw the top pixel strip at some
+    // window widths. We don't want to have a flickering transparent line, so
+    // we overdraw it.
+    CGContextSetRGBFillColor(aContext, 0.95, 0.95, 0.95, 1);
+    CGContextFillRect(aContext, CGRectMake(0, CGRectGetMaxY(aTitlebarRect) - 1,
+                                           aTitlebarRect.size.width, 1));
+  }
 }
 
 // Pattern draw callback for standard titlebar gradients and solid titlebar colors
 static void
 TitlebarDrawCallback(void* aInfo, CGContextRef aContext)
 {
   ToolbarWindow *window = (ToolbarWindow*)aInfo;
 
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -6354,17 +6354,17 @@ nsWindow::ResetRemainingWheelDelta()
 {
   sRemainingDeltaForPixel = 0;
   sRemainingDeltaForScroll = 0;
   sLastMouseWheelWnd = NULL;
 }
 
 static PRInt32 RoundDelta(double aDelta)
 {
-  return aDelta >= 0 ? (PRInt32)NS_floor(aDelta) : (PRInt32)NS_ceil(aDelta);
+  return aDelta >= 0 ? (PRInt32)floor(aDelta) : (PRInt32)ceil(aDelta);
 }
 
 /**
  * OnMouseWheelInternal - mouse wheel event processing.
  * aMessage may be WM_MOUSEWHEEL or WM_MOUSEHWHEEL but this is called when
  * ProcessMessage() handles MOZ_WM_MOUSEVWHEEL or MOZ_WM_MOUSEHWHEEL.
  */
 void
--- a/xpcom/ds/nsMathUtils.h
+++ b/xpcom/ds/nsMathUtils.h
@@ -101,40 +101,16 @@ inline NS_HIDDEN_(PRInt32) NS_lroundup30
 #endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
 
 inline NS_HIDDEN_(PRInt32) NS_lroundf(float x)
 {
     return x >= 0.0f ? PRInt32(x + 0.5f) : PRInt32(x - 0.5f);
 }
 
 /*
- * ceil
- */
-inline NS_HIDDEN_(double) NS_ceil(double x)
-{
-    return ceil(x);
-}
-inline NS_HIDDEN_(float) NS_ceilf(float x)
-{
-    return ceilf(x);
-}
-
-/*
- * floor
- */
-inline NS_HIDDEN_(double) NS_floor(double x)
-{
-    return floor(x);
-}
-inline NS_HIDDEN_(float) NS_floorf(float x)
-{
-    return floorf(x);
-}
-
-/*
  * hypot.  We don't need a super accurate version of this, if a platform
  * turns up with none of the possibilities below it would be okay to fall
  * back to sqrt(x*x + y*y).
  */
 inline NS_HIDDEN_(double) NS_hypot(double x, double y)
 {
 #if __GNUC__ >= 4
     return __builtin_hypot(x, y);