Merge m-c to m-i
authorMs2ger <ms2ger@gmail.com>
Sat, 13 Aug 2011 14:47:03 +0200
changeset 74373 19ab9ba1c62369998649c5c0192aeafc0b74a230
parent 74336 8e1dd6f8b903ccbb4fcdff817b606fda45d41311 (current diff)
parent 74372 d7ccb99a2f2d04e406e9f91ff0ecd7dd811a5ed2 (diff)
child 74374 53bbf9d8a0e5833a72eb87c5981a11bb35fa85fb
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone8.0a1
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);