Merge last green PGO build from mozilla-inbound to mozilla-central
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 29 Dec 2011 12:02:01 +0100
changeset 84707 fff9a6ac640a251fbe8e9f5e2c71759bc1a7deaf
parent 84669 5f606d407c14b09e52911b6725360d756f75cf27 (current diff)
parent 84706 54bf8b9d80bedd998eb9e8c5413c3079c1204a6c (diff)
child 84723 8ae5766168c826a8b44b7752ed54ed834f16d068
child 84730 2c661ddfed0d5e873037faf17429171c2528decd
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
Merge last green PGO build from mozilla-inbound to mozilla-central
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -142,16 +142,17 @@
 @BINPATH@/components/content_xtf.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_telephony.xpt
+@BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
@@ -391,16 +392,18 @@
 @BINPATH@/components/messageWakeupService.manifest
 @BINPATH@/components/nsFilePicker.js
 @BINPATH@/components/nsFilePicker.manifest
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/nsTelephonyWorker.manifest
 @BINPATH@/components/nsTelephonyWorker.js
 @BINPATH@/components/Telephony.manifest
 @BINPATH@/components/Telephony.js
+@BINPATH@/components/nsWifiWorker.js
+@BINPATH@/components/nsWifiWorker.manifest
 #endif
 #ifdef XP_MACOSX
 @BINPATH@/components/libalerts_s.dylib
 #endif
 #ifdef MOZ_ENABLE_DBUS
 @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
 #endif
 @BINPATH@/components/nsINIProcessor.manifest
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -42,24 +42,17 @@ tabbrowser {
                    max-width 250ms ease-out,
                    opacity 50ms ease-out 100ms /* hide the tab for the last 100ms of the max-width transition */;
 }
 
 .tab-throbber:not([fadein]):not([pinned]),
 .tab-label:not([fadein]):not([pinned]),
 .tab-icon-image:not([fadein]):not([pinned]),
 .tab-close-button:not([fadein]):not([pinned]) {
-  opacity: 0 !important;
-}
-
-.tab-throbber,
-.tab-label,
-.tab-icon-image,
-.tab-close-button {
-  -moz-transition: opacity 250ms;
+  display: none;
 }
 
 .tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] {
   position: fixed !important;
   display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
 }
 
 #alltabs-popup {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -393,30 +393,30 @@
       <iframe id="customizeToolbarSheetIFrame"
               style="&dialog.style;"
               hidden="true"/>
     </panel>
 
     <tooltip id="tabbrowser-tab-tooltip" onpopupshowing="gBrowser.createTooltip(event);"/>
 
     <tooltip id="back-button-tooltip">
-      <label value="&backButton.tooltip;"/>
+      <label class="tooltip-label" value="&backButton.tooltip;"/>
 #ifdef XP_MACOSX
-      <label value="&backForwardButtonMenuMac.tooltip;"/>
+      <label class="tooltip-label" value="&backForwardButtonMenuMac.tooltip;"/>
 #else
-      <label value="&backForwardButtonMenu.tooltip;"/>
+      <label class="tooltip-label" value="&backForwardButtonMenu.tooltip;"/>
 #endif
     </tooltip>
   
     <tooltip id="forward-button-tooltip">
-      <label value="&forwardButton.tooltip;"/>
+      <label class="tooltip-label" value="&forwardButton.tooltip;"/>
 #ifdef XP_MACOSX
-      <label value="&backForwardButtonMenuMac.tooltip;"/>
+      <label class="tooltip-label" value="&backForwardButtonMenuMac.tooltip;"/>
 #else
-      <label value="&backForwardButtonMenu.tooltip;"/>
+      <label class="tooltip-label" value="&backForwardButtonMenu.tooltip;"/>
 #endif
     </tooltip>
   </popupset>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <hbox id="appmenu-button-container">
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -133,16 +133,17 @@
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_apps.xpt
 @BINPATH@/components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_telephony.xpt
+@BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
@@ -361,16 +362,18 @@
 @BINPATH@/components/contentSecurityPolicy.js
 @BINPATH@/components/contentAreaDropListener.manifest
 @BINPATH@/components/contentAreaDropListener.js
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/nsTelephonyWorker.manifest
 @BINPATH@/components/nsTelephonyWorker.js
 @BINPATH@/components/Telephony.manifest
 @BINPATH@/components/Telephony.js
+@BINPATH@/components/nsWifiWorker.js
+@BINPATH@/components/nsWifiWorker.manifest
 #endif
 @BINPATH@/components/BrowserProfileMigrators.manifest
 @BINPATH@/components/ChromeProfileMigrator.js
 #ifdef XP_MACOSX
 @BINPATH@/components/libalerts_s.dylib
 #endif
 #ifdef MOZ_ENABLE_DBUS
 @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -65,16 +65,17 @@ components/nsExtensionManager.js
 components/nsInterfaceInfoToIDL.js
 components/nsScriptableIO.js
 components/nsUrlClassifierTable.js
 components/nsXmlRpcClient.js
 components/pluginGlue.js
 components/sidebar.xpt
 #ifdef MOZ_B2G_RIL
 components/dom_telephony.xpt
+components/dom_wifi.xpt
 components/dom_system_b2g.xpt
 #endif
 components/uconvd.dll
 components/WeaveCrypto.js
 components/WeaveCrypto.manifest
 components/xmlextras.xpt
 components/xpcom.xpt
 components/xpti.dat
@@ -917,16 +918,18 @@ xpicleanup@BIN_SUFFIX@
   components/PlacesProtocolHandler.js
   components/storage-Legacy.js
   components/storage-mozStorage.js
 #ifdef MOZ_B2G_RIL
   components/nsTelephonyWorker.manifest
   components/nsTelephonyWorker.js
   components/Telephony.manifest
   components/Telephony.js
+  components/nsWifiWorker.js
+  components/nsWifiWorker.manifest
 #endif
   components/txEXSLTRegExFunctions.js
   components/Weave.js
   components/WebContentConverter.js
   defaults/autoconfig/platform.js
   defaults/autoconfig/prefcalls.js
   defaults/pref/firefox-branding.js
   defaults/pref/firefox.js
@@ -1138,16 +1141,17 @@ xpicleanup@BIN_SUFFIX@
   components/cookie.xpt
   components/crashreporter.xpt
   components/directory.xpt
   components/docshell.xpt
   components/dom.xpt
   components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
   components/dom_telephony.xpt
+  components/dom_wifi.xpt
   components/dom_system_b2g.xpt
 #endif
   components/dom_canvas.xpt
   components/dom_core.xpt
   components/dom_css.xpt
   components/dom_events.xpt
   components/dom_geolocation.xpt
   components/dom_html.xpt
--- a/configure.in
+++ b/configure.in
@@ -1859,46 +1859,65 @@ if test "$GNU_CC"; then
     fi
     WARNINGS_AS_ERRORS='-Werror'
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-fPIC'
     ASFLAGS="$ASFLAGS -fPIC"
     _MOZ_RTTI_FLAGS_ON=-frtti
     _MOZ_RTTI_FLAGS_OFF=-fno-rtti
 
-    # Turn on GNU specific features
-    # -Wall - turn on all warnings
-    # -pedantic - make compiler warn about non-ANSI stuff, and
-    #             be a little bit stricter
-    # -Wdeclaration-after-statement - MSVC doesn't like these
-    # Warnings slamm took out for now (these were giving more noise than help):
-    # -Wbad-function-cast - warns when casting a function to a new return type
-    # -Wshadow - removed because it generates more noise than help --pete
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -W -Wno-unused -Wpointer-arith -Wdeclaration-after-statement"
+    # Turn on GNU-specific warnings:
+    # -Wall - turn on a lot of warnings
+    # -pedantic - this is turned on below
+    # -Wpointer-arith - enabled with -pedantic, but good to have even if not
+    # -Werror=declaration-after-statement - MSVC doesn't like these
+    # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
+    #
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -Wpointer-arith -Wdeclaration-after-statement -Wempty-body"
+    
+    # Turn off the following warnings that -Wall/-pedantic turn on:
+    # -Woverlength-strings - we exceed the minimum maximum length all the time
+    #
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-overlength-strings"
+
     if test -z "$INTEL_CC" -a -z "$CLANG_CC"; then
        # Don't use -Wcast-align with ICC or clang
        case "$CPU_ARCH" in
            # And don't use it on hppa, ia64, sparc, arm, since it's noisy there
            hppa | ia64 | sparc | arm)
            ;;
            *)
         _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wcast-align"
            ;;
        esac
     fi
 
     dnl Turn pedantic on but disable the warnings for long long
     _PEDANTIC=1
 
-    if test -z "$INTEL_CC"; then
-      _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -W"
-    fi
-
     _DEFINES_CFLAGS='-include $(DEPTH)/mozilla-config.h -DMOZILLA_CLIENT'
     _USE_CPP_INCLUDE_FLAG=1
+
+    AC_CACHE_CHECK(whether the compiler supports -Wtype-limits,
+                   ac_cc_has_wtype_limits,
+        [
+            AC_LANG_SAVE
+            AC_LANG_C
+            _SAVE_CFLAGS="$CFLAGS"
+            CFLAGS="$CFLAGS -Wtype-limits"
+            AC_TRY_COMPILE([],
+                           [return(0);],
+                           ac_cc_has_wtype_limits="yes",
+                           ac_cc_has_wtype_limits="no")
+            CFLAGS="$_SAVE_CFLAGS"
+            AC_LANG_RESTORE
+        ])
+    if test "$ac_cc_has_wtype_limits" = "yes"; then
+        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
+    fi
 elif test "$SOLARIS_SUNPRO_CC"; then
     DSO_CFLAGS=''
     if test "$CPU_ARCH" = "sparc"; then
         # for Sun Studio on Solaris/SPARC
         DSO_PIC_CFLAGS='-xcode=pic32'
     else
         DSO_PIC_CFLAGS='-KPIC'
     fi
@@ -1916,18 +1935,32 @@ else
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-KPIC'
     _DEFINES_CFLAGS='$(ACDEFINES) -D_MOZILLA_CONFIG_H_ -DMOZILLA_CLIENT'
 fi
 
 if test "$GNU_CXX"; then
     # FIXME: Let us build with strict aliasing. bug 414641.
     CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-strict-aliasing"
-    # Turn on GNU specific features
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor"
+
+    # Turn on GNU-specific warnings:
+    # -Wall - turn on a lot of warnings
+    # -pedantic - this is turned on below
+    # -Wpointer-arith - enabled with -pedantic, but good to have even if not
+    # -Woverloaded-virtual - ???
+    # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
+    #
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wempty-body"
+
+    # Turn off the following warnings that -Wall/-pedantic turn on:
+    # -Woverlength-strings - we exceed the minimum maximum length all the time
+    # -Wctor-dtor-privacy - ???
+    #
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-overlength-strings -Wno-ctor-dtor-privacy"
+
     if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
        # Don't use -Wcast-align with ICC or clang
        case "$CPU_ARCH" in
            # And don't use it on hppa, ia64, sparc, arm, since it's noisy there
            hppa | ia64 | sparc | arm)
            ;;
            *)
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wcast-align"
@@ -2018,16 +2051,34 @@ if test "$GNU_CXX"; then
                            ac_has_werror_return_type="no")
             CXXFLAGS="$_SAVE_CXXFLAGS"
             AC_LANG_RESTORE
         ])
     if test "$ac_has_werror_return_type" = "yes"; then
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
     fi
 
+    AC_CACHE_CHECK(whether the compiler supports -Wtype-limits,
+                   ac_has_wtype_limits,
+        [
+            AC_LANG_SAVE
+            AC_LANG_CPLUSPLUS
+            _SAVE_CXXFLAGS="$CXXFLAGS"
+            CXXFLAGS="$CXXFLAGS -Wtype-limits"
+            AC_TRY_COMPILE([],
+                           [return(0);],
+                           ac_has_wtype_limits="yes",
+                           ac_has_wtype_limits="no")
+            CXXFLAGS="$_SAVE_CXXFLAGS"
+            AC_LANG_RESTORE
+        ])
+    if test "$ac_has_wtype_limits" = "yes"; then
+        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
+    fi
+
 else
     _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_MOZILLA_CONFIG_H_ $(ACDEFINES)'
 fi
 
 dnl gcc can come with its own linker so it is better to use the pass-thru calls
 dnl MKSHLIB_FORCE_ALL is used to force the linker to include all object
 dnl files present in an archive. MKSHLIB_UNFORCE_ALL reverts the linker to
 dnl normal behavior.
--- a/content/xslt/src/base/txExpandedNameMap.h
+++ b/content/xslt/src/base/txExpandedNameMap.h
@@ -97,28 +97,26 @@ protected:
 
         bool next()
         {
             return ++mCurrentPos < mMap.mItems.Length();
         }
 
         const txExpandedName key()
         {
-            NS_ASSERTION(mCurrentPos >= 0 &&
-                         mCurrentPos < mMap.mItems.Length(),
+            NS_ASSERTION(mCurrentPos < mMap.mItems.Length(),
                          "invalid position in txExpandedNameMap::iterator");
             return txExpandedName(mMap.mItems[mCurrentPos].mNamespaceID,
                                   mMap.mItems[mCurrentPos].mLocalName);
         }
 
     protected:
         void* itemValue()
         {
-            NS_ASSERTION(mCurrentPos >= 0 &&
-                         mCurrentPos < mMap.mItems.Length(),
+            NS_ASSERTION(mCurrentPos < mMap.mItems.Length(),
                          "invalid position in txExpandedNameMap::iterator");
             return mMap.mItems[mCurrentPos].mValue;
         }
 
     private:
         txExpandedNameMap_base& mMap;
         PRUint32 mCurrentPos;
     };
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -79,17 +79,20 @@ DIRS += \
   plugins/ipc \
   indexedDB \
   system \
   ipc \
   workers \
   $(NULL)
 
 ifdef MOZ_B2G_RIL #{
-DIRS += telephony
+DIRS += \
+  telephony \
+  wifi \
+  $(NULL)
 endif #}
 
 ifdef ENABLE_TESTS
 DIRS += tests
 ifneq (,$(filter gtk2 cocoa windows android qt os2,$(MOZ_WIDGET_TOOLKIT)))
 DIRS += plugins/test
 endif
 endif
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1030,16 +1030,24 @@ Navigator::SizeOf() const
   // TODO: add SizeOf() to nsGeolocation, bug 674115.
   size += mGeolocation ? sizeof(*mGeolocation.get()) : 0;
   // TODO: add SizeOf() to nsDesktopNotificationCenter, bug 674116.
   size += mNotification ? sizeof(*mNotification.get()) : 0;
 
   return size;
 }
 
+void
+Navigator::SetWindow(nsPIDOMWindow *aInnerWindow)
+{
+  NS_ASSERTION(aInnerWindow->IsInnerWindow(),
+               "Navigator must get an inner window!");
+  mWindow = do_GetWeakReference(aInnerWindow);
+}
+
 } // namespace dom
 } // namespace mozilla
 
 nsresult
 NS_GetNavigatorUserAgent(nsAString& aUserAgent)
 {
   nsresult rv;
 
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -98,16 +98,21 @@ public:
   nsPIDOMWindow *GetWindow();
 
   void RefreshMIMEArray();
 
   static bool HasDesktopNotificationSupport();
 
   PRInt64 SizeOf() const;
 
+  /**
+   * For use during document.write where our inner window changes.
+   */
+  void SetWindow(nsPIDOMWindow *aInnerWindow);
+
 private:
   bool IsSmsAllowed() const;
   bool IsSmsSupported() const;
 
   nsRefPtr<nsMimeTypeArray> mMimeTypes;
   nsRefPtr<nsPluginArray> mPlugins;
   nsRefPtr<nsGeolocation> mGeolocation;
   nsRefPtr<nsDesktopNotificationCenter> mNotification;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1674,16 +1674,35 @@ jsid nsDOMClassInfo::sWrappedJSObject_id
 jsid nsDOMClassInfo::sURL_id             = JSID_VOID;
 jsid nsDOMClassInfo::sKeyPath_id         = JSID_VOID;
 jsid nsDOMClassInfo::sAutoIncrement_id   = JSID_VOID;
 jsid nsDOMClassInfo::sUnique_id          = JSID_VOID;
 jsid nsDOMClassInfo::sMultiEntry_id      = JSID_VOID;
 jsid nsDOMClassInfo::sOnload_id          = JSID_VOID;
 jsid nsDOMClassInfo::sOnerror_id         = JSID_VOID;
 
+static const JSClass *sObjectClass = nsnull;
+
+/**
+ * Set our JSClass pointer for the Object class
+ */
+static void
+FindObjectClass(JSObject* aGlobalObject)
+{
+  NS_ASSERTION(!sObjectClass,
+               "Double set of sObjectClass");
+  JSObject *obj, *proto = aGlobalObject;
+  do {
+    obj = proto;
+    proto = js::GetObjectProto(obj);
+  } while (proto);
+
+  sObjectClass = js::GetObjectJSClass(obj);
+}
+
 static void
 PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty)
 {
   nsCOMPtr<nsIStringBundleService> stringService =
     mozilla::services::GetStringBundleService();
   if (!stringService) {
     return;
   }
@@ -4697,62 +4716,16 @@ GetExternalClassInfo(nsScriptNameSpaceMa
 static nsresult
 ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
                  JSObject *obj, const PRUnichar *name,
                  const nsDOMClassInfoData *ci_data,
                  const nsGlobalNameStruct *name_struct,
                  nsScriptNameSpaceManager *nameSpaceManager,
                  JSObject *dot_prototype, bool install, bool *did_resolve);
 
-static nsresult
-LookupPrototypeProto(JSContext *cx, JSObject *winobj,
-                     const nsDOMClassInfoData *ci_data,
-                     const nsGlobalNameStruct *name_struct,
-                     JSObject **aProtoProto);
-
-
-static nsGlobalWindow*
-FindUsableInnerWindow(nsIXPConnect *xpc, JSContext *cx, JSObject *global)
-{
-  // Only do this if the global object is a window.
-  // XXX Is there a better way to check this?
-  nsISupports *globalNative = xpc->GetNativeOfWrapper(cx, global);
-  nsCOMPtr<nsPIDOMWindow> piwin = do_QueryInterface(globalNative);
-  if (!piwin) {
-    return nsnull;
-  }
-
-  nsGlobalWindow *win = nsGlobalWindow::FromSupports(globalNative);
-  if (win->IsClosedOrClosing()) {
-    return nsnull;
-  }
-  
-  // If the window is in a different compartment than the global object, then
-  // it's likely that global is a sandbox object whose prototype is a window.
-  // Don't do anything in this case.
-  if (win->FastGetGlobalJSObject() &&
-      js::GetObjectCompartment(global) != js::GetObjectCompartment(win->FastGetGlobalJSObject())) {
-    return nsnull;
-  }
-
-  if (win->IsOuterWindow()) {
-    // XXXjst: Do security checks here when we remove the security
-    // checks on the inner window.
-
-    win = win->GetCurrentInnerWindowInternal();
-
-    JSObject* global;
-    if (!win || !(global = win->GetGlobalJSObject()) ||
-        win->IsClosedOrClosing()) {
-      return nsnull;
-    }
-  }
-
-  return win;
-}
 
 NS_IMETHODIMP
 nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * proto)
 {
   PRUint32 flags = (mData->mScriptableFlags & DONT_ENUM_STATIC_PROPS)
                    ? 0
                    : JSPROP_ENUMERATE;
 
@@ -4761,16 +4734,29 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
     count++;
   }
 
   if (!sXPConnect->DefineDOMQuickStubs(cx, proto, flags,
                                        count, mData->mInterfaces)) {
     JS_ClearPendingException(cx);
   }
 
+  // This is called before any other location that requires
+  // sObjectClass, so compute it here. We assume that nobody has had a
+  // chance to monkey around with proto's prototype chain before this.
+  if (!sObjectClass) {
+    FindObjectClass(proto);
+    NS_ASSERTION(sObjectClass && !strcmp(sObjectClass->name, "Object"),
+                 "Incorrect object class!");
+  }
+
+  NS_ASSERTION(::JS_GetPrototype(cx, proto) &&
+               JS_GET_CLASS(cx, ::JS_GetPrototype(cx, proto)) == sObjectClass,
+               "Hmm, somebody did something evil?");
+
 #ifdef DEBUG
   if (mData->mHasClassInterface && mData->mProtoChainInterface &&
       mData->mProtoChainInterface != &NS_GET_IID(nsISupports)) {
     nsCOMPtr<nsIInterfaceInfoManager>
       iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
 
     if (iim) {
       nsCOMPtr<nsIInterfaceInfo> if_info;
@@ -4788,22 +4774,48 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
 #endif
 
   // Make prototype delegation work correctly. Consider if a site sets
   // HTMLElement.prototype.foopy = function () { ... } Now, calling
   // document.body.foopy() needs to ensure that looking up foopy on
   // document.body's prototype will find the right function.
   JSObject *global = ::JS_GetGlobalForObject(cx, proto);
 
-  nsGlobalWindow *win = FindUsableInnerWindow(XPConnect(), cx, global);
-  if (!win) {
+  // Only do this if the global object is a window.
+  // XXX Is there a better way to check this?
+  nsISupports *globalNative = XPConnect()->GetNativeOfWrapper(cx, global);
+  nsCOMPtr<nsPIDOMWindow> piwin = do_QueryInterface(globalNative);
+  if (!piwin) {
+    return NS_OK;
+  }
+
+  nsGlobalWindow *win = nsGlobalWindow::FromSupports(globalNative);
+  if (win->IsClosedOrClosing()) {
     return NS_OK;
   }
 
-  global = win->FastGetGlobalJSObject();
+  // If the window is in a different compartment than the global object, then
+  // it's likely that global is a sandbox object whose prototype is a window.
+  // Don't do anything in this case.
+  if (win->FastGetGlobalJSObject() &&
+      js::GetObjectCompartment(global) != js::GetObjectCompartment(win->FastGetGlobalJSObject())) {
+    return NS_OK;
+  }
+
+  if (win->IsOuterWindow()) {
+    // XXXjst: Do security checks here when we remove the security
+    // checks on the inner window.
+
+    win = win->GetCurrentInnerWindowInternal();
+
+    if (!win || !(global = win->GetGlobalJSObject()) ||
+        win->IsClosedOrClosing()) {
+      return NS_OK;
+    }
+  }
 
   // Don't overwrite a property set by content.
   JSBool found;
   if (!::JS_AlreadyHasOwnUCProperty(cx, global, reinterpret_cast<const jschar*>(mData->mNameUTF16),
                                     nsCRT::strlen(mData->mNameUTF16), &found)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -4812,33 +4824,16 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
   NS_ENSURE_TRUE(nameSpaceManager, NS_OK);
 
   bool unused;
   return ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
                           mData, nsnull, nameSpaceManager, proto, !found,
                           &unused);
 }
 
-NS_IMETHODIMP
-nsDOMClassInfo::PreCreatePrototype(JSContext * cx, JSObject * global,
-                                   JSObject **protoProto)
-{
-  *protoProto = nsnull;
-  
-  nsGlobalWindow *win = FindUsableInnerWindow(XPConnect(), cx, global);
-  if (!win) {
-    return NS_OK;
-  }
-
-  JSObject *winObj = win->FastGetGlobalJSObject();
-  
-  return LookupPrototypeProto(cx, winObj, mData, nsnull, protoProto);
-}
-
-
 // static
 nsIClassInfo *
 NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID)
 {
   if (aID >= eDOMClassInfoIDCount) {
     NS_ERROR("Bad ID!");
 
     return nsnull;
@@ -5181,17 +5176,17 @@ nsWindowSH::InstallGlobalScopePolluter(J
   }
 
   JSObject *o = obj, *proto;
 
   // Find the place in the prototype chain where we want this global
   // scope polluter (right before Object.prototype).
 
   while ((proto = ::JS_GetPrototype(cx, o))) {
-    if (js::GetObjectClass(proto) == &js::ObjectClass) {
+    if (JS_GET_CLASS(cx, proto) == sObjectClass) {
       // Set the global scope polluters prototype to Object.prototype
       ::JS_SplicePrototype(cx, gsp, proto);
 
       break;
     }
 
     o = proto;
   }
@@ -6003,115 +5998,16 @@ GetXPCProto(nsIXPConnect *aXPConnect, JS
   if (!JS_WrapObject(cx, &proto_obj)) {
     return NS_ERROR_FAILURE;
   }
 
   NS_IF_RELEASE(*aProto);
   return aXPConnect->HoldObject(cx, proto_obj, aProto);
 }
 
-static nsresult
-LookupPrototypeProto(JSContext *cx, JSObject *winobj,
-                     const nsDOMClassInfoData *ci_data,
-                     const nsGlobalNameStruct *name_struct,
-                     JSObject **aProtoProto)
-{
-  NS_ASSERTION(ci_data ||
-               (name_struct &&
-                name_struct->mType == nsGlobalNameStruct::eTypeClassProto),
-               "Wrong type or missing ci_data!");
-
-  const nsIID *primary_iid = &NS_GET_IID(nsISupports);
-
-  if (!ci_data) {
-    primary_iid = &name_struct->mIID;
-  } else if (ci_data->mProtoChainInterface) {
-    primary_iid = ci_data->mProtoChainInterface;
-  }
-
-  if (primary_iid->Equals(NS_GET_IID(nsISupports))) {
-    *aProtoProto = nsnull;
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIInterfaceInfoManager>
-    iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
-  NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
-
-  nsCOMPtr<nsIInterfaceInfo> if_info;
-  iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
-  NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
-
-  const nsIID *iid = nsnull;
-
-  nsCOMPtr<nsIInterfaceInfo> parent;
-  if (ci_data && !ci_data->mHasClassInterface) {
-    if_info->GetIIDShared(&iid);
-  } else {
-    if_info->GetParent(getter_AddRefs(parent));
-    NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
-
-    parent->GetIIDShared(&iid);
-  }
-
-  if (!iid || iid->Equals(NS_GET_IID(nsISupports))) {
-    *aProtoProto = nsnull;
-    return NS_OK;
-  }
-
-  const char *class_parent_name = nsnull;
-  if (ci_data && !ci_data->mHasClassInterface) {
-    // If the class doesn't have a class interface the primary
-    // interface is the interface that should be
-    // constructor.prototype.__proto__.
-
-    if_info->GetNameShared(&class_parent_name);
-  } else {
-    // If the class does have a class interface (or there's no
-    // real class for this name) then the parent of the
-    // primary interface is what we want on
-    // constructor.prototype.__proto__.
-
-    NS_ASSERTION(parent, "Whoa, this is bad, null parent here!");
-
-    parent->GetNameShared(&class_parent_name);
-  }
-
-  JSObject *protoProto = nsnull;
-
-  // Get class_parent_name here
-  if (class_parent_name) {
-    jsval val;
-
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, winobj)) {
-      return NS_ERROR_UNEXPECTED;
-    }
-
-    if (!::JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) {
-      return NS_ERROR_UNEXPECTED;
-    }
-
-    JSObject *tmp = JSVAL_IS_OBJECT(val) ? JSVAL_TO_OBJECT(val) : nsnull;
-
-    if (tmp) {
-      if (!::JS_LookupProperty(cx, tmp, "prototype", &val)) {
-        return NS_ERROR_UNEXPECTED;
-      }
-
-      if (JSVAL_IS_OBJECT(val)) {
-        protoProto = JSVAL_TO_OBJECT(val);
-      }
-    }
-  }
-
-  *aProtoProto = protoProto;
-  return NS_OK;
-}
-
 // Either ci_data must be non-null or name_struct must be non-null and of type
 // eTypeClassProto.
 static nsresult
 ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
                  JSObject *obj, const PRUnichar *name,
                  const nsDOMClassInfoData *ci_data,
                  const nsGlobalNameStruct *name_struct,
                  nsScriptNameSpaceManager *nameSpaceManager,
@@ -6147,16 +6043,20 @@ ResolvePrototype(nsIXPConnect *aXPConnec
 
   if (!ci_data) {
     primary_iid = &name_struct->mIID;
   }
   else if (ci_data->mProtoChainInterface) {
     primary_iid = ci_data->mProtoChainInterface;
   }
 
+  nsCOMPtr<nsIInterfaceInfo> if_info;
+  nsCOMPtr<nsIInterfaceInfo> parent;
+  const char *class_parent_name = nsnull;
+
   if (!primary_iid->Equals(NS_GET_IID(nsISupports))) {
     JSAutoEnterCompartment ac;
 
     if (!ac.enter(cx, class_obj)) {
       return NS_ERROR_FAILURE;
     }
 
     rv = DefineInterfaceConstants(cx, class_obj, primary_iid);
@@ -6170,36 +6070,98 @@ ResolvePrototype(nsIXPConnect *aXPConnec
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // Special case for |IDBKeyRange| which gets funny "static" functions.
     if (primary_iid->Equals(NS_GET_IID(nsIIDBKeyRange)) &&
         !indexedDB::IDBKeyRange::DefineConstructors(cx, class_obj)) {
       return NS_ERROR_FAILURE;
     }
+
+    nsCOMPtr<nsIInterfaceInfoManager>
+      iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
+    NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
+
+    iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info));
+    NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED);
+
+    const nsIID *iid = nsnull;
+
+    if (ci_data && !ci_data->mHasClassInterface) {
+      if_info->GetIIDShared(&iid);
+    } else {
+      if_info->GetParent(getter_AddRefs(parent));
+      NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
+
+      parent->GetIIDShared(&iid);
+    }
+
+    if (iid) {
+      if (!iid->Equals(NS_GET_IID(nsISupports))) {
+        if (ci_data && !ci_data->mHasClassInterface) {
+          // If the class doesn't have a class interface the primary
+          // interface is the interface that should be
+          // constructor.prototype.__proto__.
+
+          if_info->GetNameShared(&class_parent_name);
+        } else {
+          // If the class does have a class interface (or there's no
+          // real class for this name) then the parent of the
+          // primary interface is what we want on
+          // constructor.prototype.__proto__.
+
+          NS_ASSERTION(parent, "Whoa, this is bad, null parent here!");
+
+          parent->GetNameShared(&class_parent_name);
+        }
+      }
+    }
   }
 
   {
     JSObject *winobj = aWin->FastGetGlobalJSObject();
 
-    JSObject *proto;
-    rv = LookupPrototypeProto(cx, winobj, ci_data, name_struct, &proto);
-    NS_ENSURE_SUCCESS(rv, rv);
+    JSObject *proto = nsnull;
+
+    if (class_parent_name) {
+      jsval val;
+
+      JSAutoEnterCompartment ac;
+      if (!ac.enter(cx, winobj)) {
+        return NS_ERROR_UNEXPECTED;
+      }
+
+      if (!::JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) {
+        return NS_ERROR_UNEXPECTED;
+      }
+
+      JSObject *tmp = JSVAL_IS_OBJECT(val) ? JSVAL_TO_OBJECT(val) : nsnull;
+
+      if (tmp) {
+        if (!::JS_LookupProperty(cx, tmp, "prototype", &val)) {
+          return NS_ERROR_UNEXPECTED;
+        }
+
+        if (JSVAL_IS_OBJECT(val)) {
+          proto = JSVAL_TO_OBJECT(val);
+        }
+      }
+    }
 
     if (dot_prototype) {
       JSAutoEnterCompartment ac;
       if (!ac.enter(cx, dot_prototype)) {
         return NS_ERROR_UNEXPECTED;
       }
 
       JSObject *xpc_proto_proto = ::JS_GetPrototype(cx, dot_prototype);
 
       if (proto &&
           (!xpc_proto_proto ||
-           js::GetObjectClass(xpc_proto_proto) == &js::ObjectClass)) {
+           JS_GET_CLASS(cx, xpc_proto_proto) == sObjectClass)) {
         if (!JS_WrapObject(cx, &proto) ||
             !JS_SetPrototype(cx, dot_prototype, proto)) {
           return NS_ERROR_UNEXPECTED;
         }
       }
     } else {
       JSAutoEnterCompartment ac;
       if (!ac.enter(cx, winobj)) {
@@ -9576,17 +9538,17 @@ nsHTMLPluginObjElementSH::SetupProtoChai
   rv = wrapper->GetJSObjectPrototype(&my_proto);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Set 'this.__proto__' to pi
   if (!::JS_SetPrototype(cx, obj, pi_obj)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (pi_proto && js::GetObjectClass(pi_proto) != &js::ObjectClass) {
+  if (pi_proto && JS_GET_CLASS(cx, pi_proto) != sObjectClass) {
     // The plugin wrapper has a proto that's not Object.prototype, set
     // 'pi.__proto__.__proto__' to the original 'this.__proto__'
     if (pi_proto != my_proto && !::JS_SetPrototype(cx, pi_proto, my_proto)) {
       return NS_ERROR_UNEXPECTED;
     }
   } else {
     // 'pi' didn't have a prototype, or pi's proto was
     // 'Object.prototype' (i.e. pi is an NPRuntime wrapped JS object)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1983,17 +1983,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     // instead.
     if (!JS_TransplantObject(cx, mJSObject, mJSObject)) {
       return NS_ERROR_FAILURE;
     }
   } else {
     if (aState) {
       newInnerWindow = wsh->GetInnerWindow();
       mInnerWindowHolder = wsh->GetInnerWindowHolder();
-      
+
       NS_ASSERTION(newInnerWindow, "Got a state without inner window");
     } else if (thisChrome) {
       newInnerWindow = new nsGlobalChromeWindow(this);
       isChrome = true;
     } else if (mIsModalContentWindow) {
       newInnerWindow = new nsGlobalModalWindow(this);
     } else {
       newInnerWindow = new nsGlobalWindow(this);
@@ -2033,16 +2033,25 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (currentInner && currentInner->mJSObject) {
       bool termFuncSet = false;
 
       if (oldDoc == aDocument) {
+        // Move the navigator from the old inner window to the new one since
+        // this is a document.write. This is safe from a same-origin point of
+        // view because document.write can only be used by the same origin.
+        newInnerWindow->mNavigator = currentInner->mNavigator;
+        currentInner->mNavigator = nsnull;
+        if (newInnerWindow->mNavigator) {
+          newInnerWindow->mNavigator->SetWindow(newInnerWindow);
+        }
+
         // Suspend the current context's request before Pop() resumes the old
         // context's request.
         JSAutoSuspendRequest asr(cx);
 
         // Pop our context here so that we get the correct one for the
         // termination function.
         cxPusher.Pop();
 
--- a/dom/system/b2g/Makefile.in
+++ b/dom/system/b2g/Makefile.in
@@ -61,12 +61,13 @@ endif
 XPIDLSRCS = \
   nsIAudioManager.idl \
   nsIRadioWorker.idl \
   $(NULL)
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/dom/base \
   -I$(topsrcdir)/dom/telephony \
+  -I$(topsrcdir)/dom/wifi \
   -I$(topsrcdir)/content/events/src \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/system/b2g/RadioManager.cpp
+++ b/dom/system/b2g/RadioManager.cpp
@@ -40,31 +40,36 @@
 #include "RadioManager.h"
 #include "nsIRadioWorker.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "nsIJSContextStack.h"
 #include "nsIObserverService.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "jstypedarray.h"
+
 #include "nsTelephonyWorker.h"
+#include "nsITelephone.h"
+#include "nsWifiWorker.h"
+#include "nsIWifi.h"
 
 #include "nsThreadUtils.h"
 
 #if defined(MOZ_WIDGET_GONK)
 #include <android/log.h>
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
 #else
 #define LOG(args...)  printf(args);
 #endif
 
 USING_WORKERS_NAMESPACE
 using namespace mozilla::ipc;
 
 static NS_DEFINE_CID(kTelephonyWorkerCID, NS_TELEPHONYWORKER_CID);
+static NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID);
 
 // Topic we listen to for shutdown.
 #define PROFILE_BEFORE_CHANGE_TOPIC "profile-before-change"
 
 USING_TELEPHONY_NAMESPACE
 
 namespace {
 
@@ -220,69 +225,41 @@ RadioManager::Init()
   if (!obs) {
     NS_WARNING("Failed to get observer service!");
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = obs->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // The telephony worker component is a hack that gives us a global object for
-  // our own functions and makes creating the worker possible.
-  nsCOMPtr<nsIRadioWorker> worker(do_CreateInstance(kTelephonyWorkerCID));
-  NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
-
-  jsval workerval;
-  rv = worker->GetWorker(&workerval);
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ASSERTION(!JSVAL_IS_PRIMITIVE(workerval), "bad worker value");
-
   JSContext *cx;
   rv = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx);
   NS_ENSURE_SUCCESS(rv, rv);
   nsCxPusher pusher;
   if (!cx || !pusher.Push(cx, false)) {
     return NS_ERROR_FAILURE;
   }
 
-  JSObject *workerobj = JSVAL_TO_OBJECT(workerval);
-
-  JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, workerobj)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
+  rv = InitTelephone(cx);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  WorkerCrossThreadDispatcher *wctd = GetWorkerCrossThreadDispatcher(cx, workerval);
-  if (!wctd) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsRefPtr<ConnectWorkerToRIL> connection = new ConnectWorkerToRIL();
-  if (!wctd->PostTask(connection)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  // Now that we're set up, connect ourselves to the RIL thread.
-  mozilla::RefPtr<RILReceiver> receiver = new RILReceiver(wctd);
-  StartRil(receiver);
-
-  mTelephone = do_QueryInterface(worker);
-  NS_ENSURE_TRUE(mTelephone, NS_ERROR_FAILURE);
+  rv = InitWifi(cx);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 void
 RadioManager::Shutdown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   StopRil();
   mTelephone = nsnull;
+  mWifi = nsnull;
 
   mShutdown = true;
 }
 
 // static
 already_AddRefed<RadioManager>
 RadioManager::FactoryCreate()
 {
@@ -311,16 +288,69 @@ RadioManager::GetTelephone()
   if (gInstance) {
     nsCOMPtr<nsITelephone> retval = gInstance->mTelephone;
     return retval.forget();
   }
 
   return nsnull;
 }
 
+nsresult
+RadioManager::InitTelephone(JSContext *cx)
+{
+  // The telephony worker component is a hack that gives us a global object for
+  // our own functions and makes creating the worker possible.
+  nsCOMPtr<nsIRadioWorker> worker(do_CreateInstance(kTelephonyWorkerCID));
+  NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
+
+  jsval workerval;
+  nsresult rv = worker->GetWorker(&workerval);
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ASSERTION(!JSVAL_IS_PRIMITIVE(workerval), "bad worker value");
+
+  JSObject *workerobj = JSVAL_TO_OBJECT(workerval);
+
+  JSAutoRequest ar(cx);
+  JSAutoEnterCompartment ac;
+  if (!ac.enter(cx, workerobj)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  WorkerCrossThreadDispatcher *wctd = GetWorkerCrossThreadDispatcher(cx, workerval);
+  if (!wctd) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<ConnectWorkerToRIL> connection = new ConnectWorkerToRIL();
+  if (!wctd->PostTask(connection)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  // Now that we're set up, connect ourselves to the RIL thread.
+  mozilla::RefPtr<RILReceiver> receiver = new RILReceiver(wctd);
+  StartRil(receiver);
+
+  mTelephone = do_QueryInterface(worker);
+  NS_ENSURE_TRUE(mTelephone, NS_ERROR_FAILURE);
+
+  return NS_OK;
+}
+
+nsresult
+RadioManager::InitWifi(JSContext *cx)
+{
+  nsCOMPtr<nsIRadioWorker> worker(do_CreateInstance(kWifiWorkerCID));
+  NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
+
+  mWifi = do_QueryInterface(worker);
+  NS_ENSURE_TRUE(mWifi, NS_ERROR_FAILURE);
+
+  return NS_OK;
+}
+
 
 NS_IMPL_ISUPPORTS1(RadioManager, nsIObserver)
 
 NS_IMETHODIMP
 RadioManager::Observe(nsISupports* aSubject, const char* aTopic,
                       const PRUnichar* aData)
 {
   if (!strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC)) {
--- a/dom/system/b2g/RadioManager.h
+++ b/dom/system/b2g/RadioManager.h
@@ -43,17 +43,16 @@
 #include "jsapi.h"
 #include "nsComponentManagerUtils.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsServiceManagerUtils.h"
 
 #include "nsIObserver.h"
 #include "mozilla/ipc/Ril.h"
-#include "nsITelephone.h"
 
 #define TELEPHONYRADIO_CONTRACTID "@mozilla.org/telephony/radio;1"
 #define TELEPHONYRADIOINTERFACE_CONTRACTID "@mozilla.org/telephony/radio-interface;1"
 
 #define BEGIN_TELEPHONY_NAMESPACE \
   namespace mozilla { namespace dom { namespace telephony {
 #define END_TELEPHONY_NAMESPACE \
   } /* namespace telephony */ } /* namespace dom */ } /* namespace mozilla */
@@ -65,16 +64,18 @@
   {0xa5c3a6de, 0x84c4, 0x4b15, {0x86, 0x11, 0x8a, 0xeb, 0x8d, 0x97, 0xf8, 0xba}}
 
 // {a688f191-8ffc-47f3-8740-94a312cf59cb}}
 #define TELEPHONYRADIOINTERFACE_CID \
   {0xd66e7ece, 0x41b1, 0x4608, {0x82, 0x80, 0x72, 0x50, 0xa6, 0x44, 0xe6, 0x6f}}
 
 
 class nsIXPConnectJSObjectHolder;
+class nsITelephone;
+class nsIWifi;
 
 BEGIN_TELEPHONY_NAMESPACE
 
 class RadioManager : public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
@@ -87,15 +88,19 @@ public:
 
   static already_AddRefed<nsITelephone>
   GetTelephone();
 
 protected:
   RadioManager();
   ~RadioManager();
 
+  nsresult InitTelephone(JSContext *cx);
+  nsresult InitWifi(JSContext *cx);
+
   nsCOMPtr<nsITelephone> mTelephone;
+  nsCOMPtr<nsIWifi> mWifi;
   bool mShutdown;
 };
 
 END_TELEPHONY_NAMESPACE
 
 #endif // mozilla_dom_telephony_radio_h__
--- a/dom/tests/mochitest/bugs/Makefile.in
+++ b/dom/tests/mochitest/bugs/Makefile.in
@@ -147,12 +147,13 @@ include $(topsrcdir)/config/rules.mk
 		test_bug698551.html \
 		test_window_bar.html \
 		file_window_bar.html \
 		test_resize_move_windows.html \
 		test_devicemotion_multiple_listeners.html \
 		devicemotion_outer.html \
 		devicemotion_inner.html \
 		test_bug698061.html \
+		test_bug707749.html \
 		$(NULL)
 
 libs:: 	$(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/bugs/test_bug707749.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=707749
+-->
+<head>
+  <title>Test for Bug 707749</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=707749 ">Mozilla Bug 707749 </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 707749 **/
+SimpleTest.waitForExplicitFinish();
+function loaded() {
+    $('ifr').contentDocument.open();
+    $('ifr').contentDocument.close();
+    ok(true, "Don't throw an exception from contentDocument.open()");
+    SimpleTest.finish();
+}
+
+</script>
+<iframe id="ifr" onload="loaded()" src="data:text/html,<script>navigator</script>"></iframe>
+</pre>
+</body>
+</html>
+
--- a/dom/tests/mochitest/orientation/Makefile.in
+++ b/dom/tests/mochitest/orientation/Makefile.in
@@ -40,14 +40,15 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir	= dom/tests/mochitest/orientation
 
 include $(DEPTH)/config/autoconf.mk
 
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES	= \
+		bug507902-frame.html \
 		test_bug507902.html \
 		$(NULL)
 
 libs:: 	$(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
copy from dom/tests/mochitest/orientation/test_bug507902.html
copy to dom/tests/mochitest/orientation/bug507902-frame.html
--- a/dom/tests/mochitest/orientation/test_bug507902.html
+++ b/dom/tests/mochitest/orientation/bug507902-frame.html
@@ -1,38 +1,30 @@
 <!DOCTYPE HTML>
 <html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=507902
--->
 <head>
-  <title>Test for watchPosition </title>
+  <title>Frame for watchPosition </title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=507902">Mozilla Bug 507902</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
+<script type="text/javascript">
+
+var ok = window.parent.ok;
+var SimpleTest = window.parent.SimpleTest;
 
 function boom()
 {
   window.addEventListener("unload", function(){}, false);
   window.addEventListener("devicemotion", function(){}, false);
   location = "data:text/html,2";
 
   ok(1, "leak will be at the end of mochitests. so pass.");
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
 window.addEventListener("load", function() { setTimeout(boom, 0); }, false);
 
 </script>
-</pre>
 </body>
 </html>
 
--- a/dom/tests/mochitest/orientation/test_bug507902.html
+++ b/dom/tests/mochitest/orientation/test_bug507902.html
@@ -1,38 +1,36 @@
 <!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=507902
 -->
 <head>
-  <title>Test for watchPosition </title>
+  <title>Test for devicemotion</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=507902">Mozilla Bug 507902</a>
 <p id="display"></p>
-<div id="content" style="display: none">
-  
+<div id="content">
+<iframe id="frame" src="bug507902-frame.html"></iframe>
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function boom()
 {
   window.addEventListener("unload", function(){}, false);
   window.addEventListener("devicemotion", function(){}, false);
   location = "data:text/html,2";
 
   ok(1, "leak will be at the end of mochitests. so pass.");
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
-window.addEventListener("load", function() { setTimeout(boom, 0); }, false);
-
 </script>
 </pre>
 </body>
 </html>
 
new file mode 100644
--- /dev/null
+++ b/dom/wifi/Makefile.in
@@ -0,0 +1,70 @@
+# ***** 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 Telephony.
+#
+# The Initial Developer of the Original Code is
+#   The Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Ben Turner <bent.mozilla@gmail.com> (Original Author)
+#
+# 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 *****
+
+DEPTH            = ../..
+topsrcdir        = @top_srcdir@
+srcdir           = @srcdir@
+VPATH            = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE           = dom
+LIBRARY_NAME     = domwifi_s
+XPIDL_MODULE     = dom_wifi
+LIBXUL_LIBRARY   = 1
+FORCE_STATIC_LIB = 1
+
+include $(topsrcdir)/dom/dom-config.mk
+
+XPIDLSRCS = \
+  nsIWifi.idl \
+  $(NULL)
+
+EXTRA_COMPONENTS = \
+  nsWifiWorker.js \
+  nsWifiWorker.manifest \
+  $(NULL)
+
+EXTRA_JS_MODULES = \
+  libcutils.js \
+  libhardware_legacy.js \
+  libnetutils.js \
+  network_worker.js \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/dom/wifi/libcutils.js
@@ -0,0 +1,13 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+"use strict";
+
+let libcutils = (function () {
+  let library = ctypes.open("/system/lib/libcutils.so");
+
+  return {
+    property_get: library.declare("property_get", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr),
+    property_set: library.declare("property_set", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.char.ptr)
+  };
+})();
new file mode 100644
--- /dev/null
+++ b/dom/wifi/libhardware_legacy.js
@@ -0,0 +1,36 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+"use strict";
+
+let libhardware_legacy = (function () {
+  let library = ctypes.open("/system/lib/libhardware_legacy.so");
+
+  return {
+    // Load wifi driver, 0 on success, < 0 on failure.
+    load_driver: library.declare("wifi_load_driver", ctypes.default_abi, ctypes.int),
+
+    // Unload wifi driver, 0 on success, < 0 on failure.
+    unload_driver: library.declare("wifi_unload_driver", ctypes.default_abi, ctypes.int),
+
+    // Start supplicant, 0 on success, < 0 on failure.
+    start_supplicant: library.declare("wifi_start_supplicant", ctypes.default_abi, ctypes.int),
+
+    // Stop supplicant, 0 on success, < 0 on failure.
+    stop_supplicant: library.declare("wifi_stop_supplicant", ctypes.default_abi, ctypes.int),
+
+    // Open a connection to the supplicant, 0 on success, < 0 on failure.
+    connect_to_supplicant: library.declare("wifi_connect_to_supplicant", ctypes.default_abi, ctypes.int),
+
+    // Close connection to connection to the supplicant, 0 on success, < 0 on failure.
+    close_supplicant_connection: library.declare("wifi_close_supplicant_connection", ctypes.default_abi, ctypes.int),
+
+    // Block until a wifi event is returned, buf is the buffer, len is the max length of the buffer.
+    // Return value is number of bytes in buffer, or 0 if no event (no connection for instance), and < 0 on failure.
+    wait_for_event: library.declare("wifi_wait_for_event", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.size_t),
+
+    // Issue a command to the wifi driver. command is the command string, reply will hold the reply, reply_len contains
+    // the maximum reply length initially and is updated with the actual length. 0 is returned on success, < 0 on failure.
+    command: library.declare("wifi_command", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.char.ptr, ctypes.size_t.ptr),
+  };
+})();
new file mode 100644
--- /dev/null
+++ b/dom/wifi/libnetutils.js
@@ -0,0 +1,30 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+"use strict";
+
+let libnetutils = (function () {
+  let library = ctypes.open("/system/lib/libnetutils.so");
+
+  return {
+    ifc_enable: library.declare("ifc_enable", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
+    ifc_disable: library.declare("ifc_disable", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
+    ifc_add_host_route: library.declare("ifc_add_host_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int),
+    ifc_remove_host_routes: library.declare("ifc_remove_host_routes", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
+    ifc_set_default_route: library.declare("ifc_set_default_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int),
+    ifc_get_default_route: library.declare("ifc_get_default_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
+    ifc_remove_default_route: library.declare("ifc_remove_default_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
+    ifc_reset_connections: library.declare("ifc_reset_connections", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
+    ifc_configure: library.declare("ifc_configure", ctypes.default_abi, ctypes.int, ctypes.char.ptr,
+                                   ctypes.int, ctypes.int, ctypes.int, ctypes.int, ctypes.int),
+    dhcp_do_request: library.declare("dhcp_do_request", ctypes.default_abi, ctypes.int,
+                                     ctypes.char.ptr, ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr,
+                                     ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr),
+    dhcp_stop: library.declare("dhcp_stop", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
+    dhcp_release_lease: library.declare("dhcp_release_lease", ctypes.default_abi, ctypes.int, ctypes.char.ptr),
+    dhcp_get_errmsg: library.declare("dhcp_get_errmsg", ctypes.default_abi, ctypes.char.ptr),
+    dhcp_do_request_renew: library.declare("dhcp_do_request_renew", ctypes.default_abi, ctypes.int,
+                                           ctypes.char.ptr, ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr,
+                                           ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr, ctypes.int.ptr)
+  };
+})();
new file mode 100644
--- /dev/null
+++ b/dom/wifi/network_worker.js
@@ -0,0 +1,94 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+"use strict";
+
+importScripts("libhardware_legacy.js", "libnetutils.js", "libcutils.js");
+
+var cbuf = ctypes.char.array(4096)();
+var hwaddr = ctypes.uint8_t.array(6)();
+var len = ctypes.size_t();
+var ints = ctypes.int.array(8)();
+
+self.onmessage = function(e) {
+  var data = e.data;
+  var id = data.id;
+  var cmd = data.cmd;
+
+  switch (cmd) {
+  case "command":
+    len.value = 4096;
+    var ret = libhardware_legacy.command(data.request, cbuf, len.address());
+    dump("For command " + data.request + " ret is " + ret + "\n");
+    var reply = "";
+    if (!ret) {
+      var reply_len = len.value;
+      var str = cbuf.readString();
+      if (str[reply_len-1] == "\n")
+        --reply_len;
+      reply = str.substr(0, reply_len);
+    }
+    postMessage({ id: id, status: ret, reply: reply });
+    break;
+  case "wait_for_event":
+    var ret = libhardware_legacy.wait_for_event(cbuf, 4096);
+    var event = cbuf.readString().substr(0, ret.value);
+    postMessage({ id: id, event: event });
+    break;
+  case "ifc_enable":
+  case "ifc_disable":
+  case "ifc_remove_host_routes":
+  case "ifc_remove_default_route":
+  case "ifc_reset_connections":
+  case "dhcp_stop":
+  case "dhcp_release_lease":
+    var ret = libnetutils[cmd](data.ifname);
+    postMessage({ id: id, status: ret });
+    break;
+  case "ifc_get_default_route":
+    var route = libnetutils.ifc_get_default_route(data.ifname);
+    postMessage({ id: id, route: route });
+    break;
+  case "ifc_add_host_route":
+  case "ifc_set_default_route":
+    var ret = libnetutils[cmd](data.ifname, data.route);
+    postMessage({ id: id, status: ret });
+    break;
+  case "ifc_configure":
+    dump("WIFI: data: " + uneval(data) + "\n");
+    var ret = libnetutils.ifc_configure(data.ifname, data.ipaddr, data.mask, data.gateway, data.dns1, data.dns2);
+    postMessage({ id: id, status: ret });
+    break;
+  case "dhcp_get_errmsg":
+    var error = libnetutils.get_dhcp_get_errmsg();
+    postMessage({ id: id, error: error.readString() });
+    break;
+  case "dhcp_do_request":
+  case "dhcp_do_request_renew":
+    var ret = libnetutils[cmd](data.ifname,
+                               ints.addressOfElement(0),
+                               ints.addressOfElement(1),
+                               ints.addressOfElement(2),
+                               ints.addressOfElement(3),
+                               ints.addressOfElement(4),
+                               ints.addressOfElement(5),
+                               ints.addressOfElement(6));
+    postMessage({ id: id, status: ret, ipaddr: ints[0], gateway: ints[1], mask: ints[2],
+                  dns1: ints[3], dns2: ints[4], server: ints[5], lease: ints[6]});
+    break;
+  case "property_get":
+    var ret = libcutils.property_get(data.key, cbuf, data.defaultValue);
+    postMessage({ id: id, status: ret, value: cbuf.readString() });
+    break;
+  case "property_set":
+    var ret = libcutils.property_set(data.key, data.value);
+    postMessage({ id: id, status: ret });
+    break;
+  default:
+    var f = libhardware_legacy[cmd] || libnetutils[cmd];
+    var ret = f();
+    dump("WIFI: " + cmd + " returned: " + ret);
+    postMessage({ id: id, status: ret });
+    break;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/wifi/nsIWifi.idl
@@ -0,0 +1,42 @@
+/* ***** 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 Telephony.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Philipp von Weitershausen <philipp@weitershausen.de>
+ *
+ * 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 ***** */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(9DCE05BF-659C-4427-A050-0EAC3BB6C1C0)]
+interface nsIWifi : nsISupports {
+};
new file mode 100644
--- /dev/null
+++ b/dom/wifi/nsWifiWorker.h
@@ -0,0 +1,40 @@
+/* ***** 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 Telephony.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben Turner <bent.mozilla@gmail.com> (Original Author)
+ *
+ * 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 ***** */
+
+#define NS_WIFIWORKER_CID \
+{ 0xA14E8977, 0xD259, 0x433A, \
+  { 0xA8, 0x8D, 0x58, 0xDD, 0x44, 0x65, 0x7E, 0x5B } }
new file mode 100644
--- /dev/null
+++ b/dom/wifi/nsWifiWorker.js
@@ -0,0 +1,853 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* ***** 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 Telephony.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Andreas Gal <gal@mozilla.com>
+ *   Blake Kaplan <mrbkap@gmail.com>
+ *
+ * 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 ***** */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const DEBUG = true; // set to false to suppress debug messages
+
+const WIFIWORKER_CONTRACTID = "@mozilla.org/wifi/worker;1";
+const WIFIWORKER_CID        = Components.ID("{a14e8977-d259-433a-a88d-58dd44657e5b}");
+
+const WIFIWORKER_WORKER     = "resource://gre/modules/network_worker.js";
+
+var WifiManager = (function() {
+  var controlWorker = new ChromeWorker(WIFIWORKER_WORKER);
+  var eventWorker = new ChromeWorker(WIFIWORKER_WORKER);
+
+  // Callbacks to invoke when a reply arrives from the controlWorker.
+  var controlCallbacks = Object.create(null);
+  var idgen = 0;
+
+  function controlMessage(obj, callback) {
+    var id = idgen++;
+    obj.id = id;
+    if (callback)
+      controlCallbacks[id] = callback;
+    controlWorker.postMessage(obj);
+  }
+
+  function onerror(e) {
+    // It is very important to call preventDefault on the event here.
+    // If an exception is thrown on the worker, it bubbles out to the
+    // component that created it. If that component doesn't have an
+    // onerror handler, the worker will try to call the error reporter
+    // on the context it was created on. However, That doesn't work
+    // for component contexts and can result in crashes. This onerror
+    // handler has to make sure that it calls preventDefault on the
+    // incoming event.
+    e.preventDefault();
+
+    var worker = (this === controlWorker) ? "control" : "event";
+
+    debug("Got an error from the " + worker + " worker: " + e.filename +
+          ":" + e.lineno + ": " + e.message + "\n");
+  }
+
+  controlWorker.onerror = onerror;
+  eventWorker.onerror = onerror;
+
+  controlWorker.onmessage = function(e) {
+    var data = e.data;
+    var id = data.id;
+    var callback = controlCallbacks[id];
+    if (callback) {
+      callback(data);
+      delete controlCallbacks[id];
+    }
+  };
+
+  // Polling the status worker
+  var recvErrors = 0;
+  eventWorker.onmessage = function(e) {
+    // process the event and tell the event worker to listen for more events
+    if (handleEvent(e.data.event))
+      waitForEvent();
+  };
+
+  function waitForEvent() {
+    eventWorker.postMessage({ cmd: "wait_for_event" });
+  }
+
+  // Commands to the control worker
+
+  function voidControlMessage(cmd, callback) {
+    controlMessage({ cmd: cmd }, function (data) {
+      callback(data.status);
+    });
+  }
+
+  function loadDriver(callback) {
+    voidControlMessage("load_driver", callback);
+  }
+
+  function unloadDriver(callback) {
+    voidControlMessage("unload_driver", callback);
+  }
+
+  function startSupplicant(callback) {
+    voidControlMessage("start_supplicant", callback);
+  }
+
+  function stopSupplicant(callback) {
+    voidControlMessage("stop_supplicant", callback);
+  }
+
+  function connectToSupplicant(callback) {
+    voidControlMessage("connect_to_supplicant", callback);
+  }
+
+  function closeSupplicantConnection(callback) {
+    voidControlMessage("close_supplicant_connection", callback);
+  }
+
+  function doCommand(request, callback) {
+    controlMessage({ cmd: "command", request: request }, callback);
+  }
+
+  function doIntCommand(request, callback) {
+    doCommand(request, function(data) {
+      callback(data.status ? -1 : (data.reply|0));
+    });
+  }
+
+  function doBooleanCommand(request, expected, callback) {
+    doCommand(request, function(data) {
+      callback(data.status ? false : (data.reply == expected));
+    });
+  }
+
+  function doStringCommand(request, callback) {
+    doCommand(request, function(data) {
+      callback(data.status ? null : data.reply);
+    });
+  }
+
+  function listNetworksCommand(callback) {
+    doStringCommand("LIST_NETWORKS", callback);
+  }
+
+  function addNetworkCommand(callback) {
+    doIntCommand("ADD_NETWORK", callback);
+  }
+
+  function setNetworkVariableCommand(netId, name, value, callback) {
+    doBooleanCommand("SET_NETWORK " + netId + " " + name + " " + value, "OK", callback);
+  }
+
+  function getNetworkVariableCommand(netId, name, callback) {
+    doStringCommand("GET_NETWORK " + netId + " " + name, callback);
+  }
+
+  function removeNetworkCommand(netId, callback) {
+    doBooleanCommand("REMOVE_NETWORK " + netId, callback);
+  }
+
+  function enableNetworkCommand(netId, disableOthers, callback) {
+    doBooleanCommand((disableOthers ? "SELECT_NETWORK " : "ENABLE_NETWORK ") + netId, "OK", callback);
+  }
+
+  function disableNetworkCommand(netId, callback) {
+    doBooleanCommand("DISABLE_NETWORK " + netId, "OK", callback);
+  }
+
+  function statusCommand(callback) {
+    doStringCommand("STATUS", callback);
+  }
+
+  function pingCommand(callback) {
+    doBooleanCommand("PING", "PONG", callback);
+  }
+
+  function scanResultsCommand(callback) {
+    doStringCommand("SCAN_RESULTS", callback);
+  }
+
+  function disconnectCommand(callback) {
+    doBooleanCommand("DISCONNECT", "OK", callback);
+  }
+
+  function reconnectCommand(callback) {
+    doBooleanCommand("RECONNECT", "OK", callback);
+  }
+
+  function reassociateCommand(callback) {
+    doBooleanCommand("REASSOCIATE", "OK", callback);
+  }
+
+  var scanModeActive = false;
+
+  function doSetScanModeCommand(setActive, callback) {
+    doBooleanCommand(setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE", "OK", callback);
+  }
+
+  function scanCommand(forceActive, callback) {
+    if (forceActive && !scanModeActive) {
+      doSetScanModeCommand(true, function(ok) {
+        ok && doBooleanCommand("SCAN", "OK", function(ok) {
+          ok && doSetScanModeCommand(false, callback);
+        });
+      });
+      return;
+    }
+    doBooleanCommand("SCAN", "OK", callback);
+  }
+
+  function setScanModeCommand(setActive, callback) {
+    sScanModeActive = setActive;
+    doSetScanModeCommand(setActive, callback);
+  }
+
+  function startDriverCommand(callback) {
+    doBooleanCommand("DRIVER START", "OK");
+  }
+
+  function stopDriverCommand(callback) {
+    doBooleanCommand("DRIVER STOP", "OK");
+  }
+
+  function startPacketFiltering(callback) {
+    doBooleanCommand("DRIVER RXFILTER-ADD 0", "OK", function(ok) {
+      ok && doBooleanCommand("DRIVER RXFILTER-ADD 1", "OK", function(ok) {
+        ok && doBooleanCommand("DRIVER RXFILTER-ADD 3", "OK", function(ok) {
+          ok && doBooleanCommand("DRIVER RXFILTER-START", "OK", callback)
+        });
+      });
+    });
+  }
+
+  function stopPacketFiltering(callback) {
+    doBooleanCommand("DRIVER RXFILTER-STOP", "OK", function(ok) {
+      ok && doBooleanCommand("DRIVER RXFILTER-REMOVE 3", "OK", function(ok) {
+        ok && doBooleanCommand("DRIVER RXFILTER-REMOVE 1", "OK", function(ok) {
+          ok && doBooleanCommand("DRIVER RXFILTER-REMOVE 0", "OK", callback)
+        });
+      });
+    });
+  }
+
+  function doGetRssiCommand(cmd, callback) {
+    doCommand(cmd, function(data) {
+      var rssi = -200;
+
+      if (!data.status) {
+        // If we are associating, the reply is "OK".
+        var reply = data.reply;
+        if (reply != "OK") {
+          // Format is: <SSID> rssi XX". SSID can contain spaces.
+          var offset = reply.lastIndexOf("rssi ");
+          if (offset != -1)
+            rssi = reply.substr(offset + 5) | 0;
+        }
+      }
+      callback(rssi);
+    });
+  }
+
+  function getRssiCommand(callback) {
+    doGetRssiCommand("DRIVER RSSI", callback);
+  }
+
+  function getRssiApproxCommand(callback) {
+    doGetRssiCommand("DRIVER RSSI-APPROX", callback);
+  }
+
+  function getLinkSpeedCommand(callback) {
+    doStringCommand("DRIVER LINKSPEED", function(reply) {
+      if (reply)
+        reply = reply.split()[1] | 0; // Format: LinkSpeed XX
+      callback(reply);
+    });
+  }
+
+  function getMacAddressCommand(callback) {
+    doStringCommand("DRIVER MACADDR", function(reply) {
+      if (reply)
+        reply = reply.split(" ")[2]; // Format: Macaddr = XX.XX.XX.XX.XX.XX
+      callback(reply);
+    });
+  }
+
+  function setPowerModeCommand(mode, callback) {
+    doBooleanCommand("DRIVER POWERMODE " + mode, "OK", callback);
+  }
+
+  function getPowerModeCommand(callback) {
+    doStringCommand("DRIVER GETPOWER", function(reply) {
+      if (reply)
+        reply = (reply.split()[2]|0); // Format: powermode = XX
+      callback(reply);
+    });
+  }
+
+  function setNumAllowedChannelsCommand(numChannels, callback) {
+    doBooleanCommand("DRIVER SCAN-CHANNELS " + numChannels, "OK", callback);
+  }
+
+  function getNumAllowedChannelsCommand(callback) {
+    doStringCommand("DRIVER SCAN-CHANNELS", function(reply) {
+      if (reply)
+        reply = (reply.split()[2]|0); // Format: Scan-Channels = X
+      callback(reply);
+    });
+  }
+
+  function setBluetoothCoexistenceModeCommand(mode, callback) {
+    doBooleanCommand("DRIVER BTCOEXMODE " + mode, "OK", callback);
+  }
+
+  function setBluetoothCoexistenceScanModeCommand(mode, callback) {
+    doBooleanCommand("DRIVER BTCOEXSCAN-" + (mode ? "START" : "STOP"), "OK", callback);
+  }
+
+  function saveConfigCommand(callback) {
+    // Make sure we never write out a value for AP_SCAN other than 1
+    doBooleanCommand("AP_SCAN 1", "OK", function(ok) {
+      doBooleanCommand("SAVE_CONFIG", "OK", callback);
+    });
+  }
+
+  function reloadConfigCommand(callback) {
+    doBooleanCommand("RECONFIGURE", "OK", callback);
+  }
+
+  function setScanResultHandlingCommand(mode, callback) {
+    doBooleanCommand("AP_SCAN " + mode, "OK", callback);
+  }
+
+  function addToBlacklistCommand(bssid, callback) {
+    doBooleanCommand("BLACKLIST " + bssid, "OK", callback);
+  }
+
+  function clearBlacklistCommand(callback) {
+    doBooleanCommand("BLACKLIST clear", "OK", callback);
+  }
+
+  function setSuspendOptimizationsCommand(enabled, callback) {
+    doBooleanCommand("DRIVER SETSUSPENDOPT " + (enabled ? 0 : 1), "OK", callback);
+  }
+
+  function getProperty(key, defaultValue, callback) {
+    controlMessage({ cmd: "property_get", key: key, defaultValue: defaultValue }, function(data) {
+      callback(data.status < 0 ? null : data.value);
+    });
+  }
+
+  function setProperty(key, value, callback) {
+    controlMessage({ cmd: "property_set", key: key, value: value }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function enableInterface(ifname, callback) {
+    controlMessage({ cmd: "ifc_enable", ifname: ifname }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function disableInterface(ifname, callback) {
+    controlMessage({ cmd: "ifc_disable", ifname: ifname }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function addHostRoute(ifname, route, callback) {
+    controlMessage({ cmd: "ifc_add_host_route", ifname: ifname, route: route }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function removeHostRoutes(ifname, callback) {
+    controlMessage({ cmd: "ifc_remove_host_routes", ifname: ifname }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function setDefaultRoute(ifname, route, callback) {
+    controlMessage({ cmd: "ifc_set_default_route", ifname: ifname, route: route }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function getDefaultRoute(ifname, callback) {
+    controlMessage({ cmd: "ifc_get_default_route", ifname: ifname }, function(data) {
+      callback(!data.route);
+    });
+  }
+
+  function removeDefaultRoute(ifname, callback) {
+    controlMessage({ cmd: "ifc_remove_default_route", ifname: ifname }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function resetConnections(ifname, callback) {
+    controlMessage({ cmd: "ifc_reset_connections", ifname: ifname }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function runDhcp(ifname, callback) {
+    controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
+      callback(data.status ? null : data);
+    });
+  }
+
+  function stopDhcp(ifname, callback) {
+    controlMessage({ cmd: "dhcp_stop", ifname: ifname }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function releaseDhcpLease(ifname, callback) {
+    controlMessage({ cmd: "dhcp_release_lease", ifname: ifname }, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function getDhcpError(callback) {
+    controlMessage({ cmd: "dhcp_get_errmsg" }, function(data) {
+      callback(data.error);
+    });
+  }
+
+  function configureInterface(ifname, ipaddr, mask, gateway, dns1, dns2, callback) {
+    controlMessage({ cmd: "ifc_configure", ifname: ifname,
+                     ipaddr: ipaddr, mask: mask, gateway: gateway,
+                     dns1: dns1, dns2: dns2}, function(data) {
+      callback(!data.status);
+    });
+  }
+
+  function runDhcpRenew(ifname, callback) {
+    controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
+      callback(data.status ? null : data);
+    });
+  }
+
+  var manager = {};
+
+  function notify(eventName, eventObject) {
+    var handler = manager["on" + eventName];
+    if (handler) {
+      if (!eventObject)
+        eventObject = ({});
+      handler.call(eventObject);
+    }
+  }
+
+  // try to connect to the supplicant
+  var connectTries = 0;
+  var retryTimer = null;
+  function connectCallback(ok) {
+    if (ok === 0) {
+      // tell the event worker to start waiting for events
+      retryTimer = null;
+      waitForEvent();
+      notify("supplicantconnection");
+      return;
+    }
+    if (connectTries++ < 3) {
+      // try again in 5 seconds
+      if (!retryTimer)
+        retryTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+
+      retryTimer.initWithCallback(function(timer) {
+          connectToSupplicant(connectCallback);
+        }, 5000, Ci.nsITimer.TYPE_ONE_SHOT);
+      return;
+    }
+
+    retryTimer = null;
+    notify("supplicantlost");
+  }
+
+  manager.start = function() {
+    connectToSupplicant(connectCallback);
+  }
+
+  var supplicantStatesMap = ["DISCONNECTED", "INACTIVE", "SCANNING", "ASSOCIATING",
+                             "FOUR_WAY_HANDSHAKE", "GROUP_HANDSHAKE", "COMPLETED",
+                             "DORMANT", "UNINITIALIZED"];
+  var driverEventMap = { STOPPED: "driverstopped", STARTED: "driverstarted", HANGED: "driverhung" };
+
+  // handle events sent to us by the event worker
+  function handleEvent(event) {
+    debug("Event coming in: " + event);
+    if (event.indexOf("CTRL-EVENT-") !== 0) {
+      debug("Got weird event, possibly not doing anything.");
+      if (event.indexOf("WPA:") == 0 &&
+          event.indexOf("pre-shared key may be incorrect") != -1) {
+        notify("passwordmaybeincorrect");
+      }
+      return true;
+    }
+
+    var eventData = event.substr(0, event.indexOf(" ") + 1);
+    if (eventData.indexOf("CTRL-EVENT-STATE-CHANGE") === 0) {
+      // Parse the event data
+      var fields = {};
+      var tokens = eventData.split(" ");
+      for (var n = 0; n < tokens.length; ++n) {
+        var kv = tokens[n].split("=");
+        if (kv.length === 2)
+          fields[kv[0]] = kv[1];
+      }
+      if (!("state" in fields))
+        return true;
+      fields.state = supplicantStatesMap[fields.state];
+      notify("statechange", fields);
+      return true;
+    }
+    if (eventData.indexOf("CTRL-EVENT-DRIVER-STATE") === 0) {
+      var handlerName = driverEventMap[eventData];
+      if (handlerName)
+        notify(handlerName);
+      return true;
+    }
+    if (eventData.indexOf("CTRL-EVENT-TERMINATING") === 0) {
+      // If the monitor socket is closed, we have already stopped the
+      // supplicant and we can stop waiting for more events and
+      // simply exit here (we don't have to notify).
+      if (eventData.indexOf("connection closed") !== -1)
+        return false;
+
+      // As long we haven't seen too many recv errors yet, we
+      // will keep going for a bit longer
+      if (eventData.indexOf("recv error") !== -1 && ++recvErrors < 10)
+        return true;
+
+      notify("supplicantlost");
+      return false;
+    }
+    if (eventData.indexOf("CTRL-EVENT-DISCONNECTED") === 0) {
+      notify("statechange", { state: "DISCONNECTED" });
+      return true;
+    }
+    if (eventData.indexOf("CTRL-EVENT-CONNECTED") === 0) {
+      // Format: CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]
+      var bssid = eventData.split(" ")[4];
+      var id = eventData.substr(eventData.indexOf("id=")).split(" ")[0];
+      notify("statechange", { state: "CONNECTED", BSSID: bssid, id: id });
+      return true;
+    }
+    if (eventData.indexOf("CTRL-EVENT-SCAN-RESULTS") === 0) {
+      debug("Notifying of scn results available");
+      notify("scanresultsavailable");
+      return true;
+    }
+    // unknown event
+    return true;
+  }
+
+  // Initial state
+  var airplaneMode = false;
+
+  // Public interface of the wifi service
+  manager.setWifiEnabled = function(enable, callback) {
+    var targetState = enable ? "ENABLED" : "DISABLED";
+    if (enable == targetState)
+      return true;
+    if (enable && airplaneMode)
+      return false;
+    if (enable) {
+      loadDriver(function (ok) {
+        (ok === 0) ? startSupplicant(callback) : callback(-1);
+      });
+    } else {
+      stopSupplicant(function (ok) {
+        (ok === 0) ? unloadDriver(callback) : callback(-1);
+      });
+    }
+  }
+
+  manager.disconnect = disconnectCommand;
+  manager.reconnect = reconnectCommand;
+  manager.reassociate = reassociateCommand;
+
+  var networkConfigurationFields = ["ssid", "bssid", "psk", "wep_key0", "wep_key1", "wep_key2", "wep_key3",
+                                    "wep_tx_keyidx", "priority", "key_mgmt", "scan_ssid"];
+
+  manager.getNetworkConfiguration = function(config, callback) {
+    var netId = config.netId;
+    var done = 0;
+    for (var n = 0; n < networkConfigurationFields; ++n) {
+      var fieldName = networkConfigurationFields[n];
+      getNetworkVariableCommand(netId, fieldName, function(value) {
+        config[fieldName] = value;
+        if (++done == networkConfigurationFields.length)
+          callback(config);
+      });
+    }
+  }
+  manager.setNetworkConfiguration = function(config, callback) {
+    var netId = config.netId;
+    var done = 0;
+    var errors = 0;
+    for (var n = 0; n < networkConfigurationFields.length; ++n) {
+      var fieldName = networkConfigurationFields[n];
+      if (!(fieldName in config)) {
+        ++done;
+      } else {
+        setNetworkVariableCommand(netId, fieldName, config[fieldName], function(ok) {
+          if (!ok)
+            ++errors;
+          if (++done == networkConfigurationFields.length)
+            callback(errors == 0);
+        });
+      }
+    }
+    // If config didn't contain any of the fields we want, don't lose the error callback
+    if (done == networkConfigurationFields.length)
+      callback(false);
+  }
+  manager.getConfiguredNetworks = function(callback) {
+    listNetworksCommand(function (reply) {
+      var networks = {};
+      var done = 0;
+      var errors = 0;
+      var lines = reply.split("\n");
+      for (var n = 1; n < lines.length; ++n) {
+        var result = lines[n].split("\t");
+        var netId = result[0];
+        var config = networks[netId] = { netId: netId };
+        switch (result[3]) {
+        case "[CURRENT]":
+          config.status = "CURRENT";
+          break;
+        case "[DISABLED]":
+          config.status = "DISABLED";
+          break;
+        default:
+          config.status = "ENABLED";
+          break;
+        }
+        manager.getNetworkConfiguration(config, function (ok) {
+            if (!ok)
+              ++errors;
+            if (++done == lines.length - 1) {
+              if (errors) {
+                // If an error occured, delete the new netId
+                removeNetworkCommand(netId, function() {
+                  callback(null);
+                });
+              } else {
+                callback(networks);
+              }
+            }
+        });
+      }
+    });
+  }
+  manager.addNetwork = function(config, callback) {
+    addNetworkCommand(function (netId) {
+      config.netId = netId;
+      manager.setNetworkConfiguration(config, callback);
+    });
+  }
+  manager.updateNetwork = function(config, callback) {
+    manager.setNetworkConfiguration(config, callback);
+  }
+  manager.removeNetwork = function(netId, callback) {
+    removeNetworkCommand(netId, callback);
+  }
+
+  function ipToString(n) {
+    return String((n & (0xff << 24)) >> 24) + "." +
+                 ((n & (0xff << 16)) >> 16) + "." +
+                 ((n & (0xff <<  8)) >>  8) + "." +
+                 ((n & (0xff <<  0)) >>  0);
+  }
+
+  manager.enableNetwork = function(netId, disableOthers, callback) {
+    getProperty("wifi.interface", "tiwlan0", function (ifname) {
+      if (!ifname) {
+        callback(false);
+        return;
+      }
+      enableInterface(ifname, function (ok) {
+        if (!ok) {
+          callback(false);
+          return;
+        }
+        enableNetworkCommand(netId, disableOthers, function (ok) {
+          if (!ok) {
+            disableInterface(ifname, function () {
+              callback(false);
+            });
+            return;
+          }
+          runDhcp(ifname, function (data) {
+            debug("After running dhcp, got data: " + uneval(data));
+            if (!data) {
+              disableInterface(ifname, function() {
+                callback(false);
+              });
+              return;
+            }
+            setProperty("net.dns1", ipToString(data.dns1), function(ok) {
+              if (!ok) {
+                callback(false);
+                return;
+              }
+              getProperty("net.dnschange", "0", function(value) {
+                if (value === null) {
+                  callback(false);
+                  return;
+                }
+                setProperty("net.dnschange", String(Number(value) + 1), function(ok) {
+                  callback(ok);
+                });
+              });
+            });
+          });
+        });
+      });
+    });
+  }
+  manager.disableNetwork = function(netId, callback) {
+    disableNetworkCommand(netId, callback);
+  }
+  manager.getMacAddress = getMacAddressCommand;
+  manager.getScanResults = scanResultsCommand;
+  return manager;
+})();
+
+function nsWifiWorker() {
+  WifiManager.onsupplicantconnection = function() {
+    debug("Connected to supplicant");
+    WifiManager.getMacAddress(function (mac) {
+      debug("Got mac: " + mac);
+    });
+  }
+  WifiManager.onsupplicantlost = function() {
+    debug("Couldn't connect to supplicant");
+  }
+
+  var networks = Object.create(null);
+  WifiManager.onscanresultsavailable = function() {
+    debug("Scan results are available! Asking for them.");
+    if (networks["Mozilla Guest"])
+      return;
+    WifiManager.getScanResults(function(r) {
+      let lines = r.split("\n");
+      // NB: Skip the header line.
+      let added = !("Mozilla Guest" in networks);
+      for (let i = 1; i < lines.length; ++i) {
+        // bssid / frequency / signal level / flags / ssid
+        var match = /([\S]+)\s+([\S]+)\s+([\S]+)\s+(\[[\S]+\])?\s+(.*)/.exec(lines[i])
+        if (match)
+          networks[match[5]] = match[1];
+        else
+          debug("Match didn't find anything for: " + lines[i]);
+      }
+
+      if (("Mozilla Guest" in networks) && added) {
+        debug("Mozilla Guest exists in networks, trying to connect!");
+        var config = Object.create(null);
+        config["ssid"] = '"Mozilla Guest"';
+        //config["bssid"] = '"' + networks["Mozilla Guest"] + '"';
+        config["key_mgmt"] = "NONE";
+        config["scan_ssid"] = 1;
+        WifiManager.addNetwork(config, function (ok) {
+          if (ok) {
+            WifiManager.enableNetwork(config.netId, false, function (ok) {
+              if (ok)
+                debug("Enabled the network!");
+              else
+                debug("Failed to enable the network :(");
+            });
+          } else {
+            debug("Failed to add the network :(");
+          }
+        });
+      }
+    });
+  }
+
+  WifiManager.setWifiEnabled(true, function (ok) {
+      if (ok === 0)
+        WifiManager.start();
+      else
+        debug("Couldn't start Wifi");
+    });
+
+  debug("Wifi starting");
+}
+
+nsWifiWorker.prototype = {
+  classID:   WIFIWORKER_CID,
+  classInfo: XPCOMUtils.generateCI({classID: WIFIWORKER_CID,
+                                    contractID: WIFIWORKER_CONTRACTID,
+                                    classDescription: "WifiWorker",
+                                    interfaces: [Ci.nsIRadioWorker,
+                                                 Ci.nsIWifi]}),
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioWorker,
+                                         Ci.nsIWifi]),
+
+  setWifiEnabled: function(enable) {
+    WifiManager.setWifiEnabled(enable, function (ok) {
+      debug(ok);
+    });
+  },
+
+  // This is a bit ugly, but works. In particular, this depends on the fact
+  // that RadioManager never actually tries to get the worker from us.
+  get worker() { throw "Not implemented"; },
+
+  shutdown: function() {
+    this.setWifiEnabled(false);
+  }
+};
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([nsWifiWorker]);
+
+let debug;
+if (DEBUG) {
+  debug = function (s) {
+    dump("-*- nsWifiWorker component: " + s + "\n");
+  };
+} else {
+  debug = function (s) {};
+}
new file mode 100644
--- /dev/null
+++ b/dom/wifi/nsWifiWorker.manifest
@@ -0,0 +1,1 @@
+component {a14e8977-d259-433a-a88d-58dd44657e5b} nsWifiWorker.js
--- a/extensions/spellcheck/src/mozPersonalDictionary.cpp
+++ b/extensions/spellcheck/src/mozPersonalDictionary.cpp
@@ -162,17 +162,17 @@ NS_IMETHODIMP mozPersonalDictionary::Loa
   
   return res;
 }
 
 // A little helper function to add the key to the list.
 // This is not threadsafe, and only safe if the consumer does not 
 // modify the list.
 static PLDHashOperator
-AddHostToStringArray(nsUniCharEntry *aEntry, void *aArg)
+AddHostToStringArray(nsUnicharPtrHashKey *aEntry, void *aArg)
 {
   static_cast<nsTArray<nsString>*>(aArg)->AppendElement(nsDependentString(aEntry->GetKey()));
   return PL_DHASH_NEXT;
 }
 
 /* void Save (); */
 NS_IMETHODIMP mozPersonalDictionary::Save()
 {
--- a/extensions/spellcheck/src/mozPersonalDictionary.h
+++ b/extensions/spellcheck/src/mozPersonalDictionary.h
@@ -43,70 +43,39 @@
 #include "nsVoidArray.h"
 #include "mozIPersonalDictionary.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "nsTHashtable.h"
 #include "nsCRT.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsHashKeys.h"
 
 #define MOZ_PERSONALDICTIONARY_CONTRACTID "@mozilla.org/spellchecker/personaldictionary;1"
 #define MOZ_PERSONALDICTIONARY_CID         \
 { /* 7EF52EAF-B7E1-462B-87E2-5D1DBACA9048 */  \
 0X7EF52EAF, 0XB7E1, 0X462B, \
   { 0X87, 0XE2, 0X5D, 0X1D, 0XBA, 0XCA, 0X90, 0X48 } }
 
-class nsUniCharEntry : public PLDHashEntryHdr
-{
-public:
-  // Hash methods
-  typedef const PRUnichar* KeyType;
-  typedef const PRUnichar* KeyTypePointer;
-
-  nsUniCharEntry(const PRUnichar* aKey) : mKey(nsCRT::strdup(aKey)) {}
-  nsUniCharEntry(const nsUniCharEntry& toCopy)
-  { 
-    NS_NOTREACHED("ALLOW_MEMMOVE is set, so copy ctor shouldn't be called");
-  }
-
-  ~nsUniCharEntry()
-  { 
-    if (mKey)
-      nsCRT::free(mKey);
-  }
- 
-  KeyType GetKey() const { return mKey; }
-  bool KeyEquals(KeyTypePointer aKey) const { return !nsCRT::strcmp(mKey, aKey); }
-  static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
-
-  static PLDHashNumber HashKey(KeyTypePointer aKey) { return nsCRT::HashCode(aKey); }
-
-  enum { ALLOW_MEMMOVE = true };
-
-private:
-  PRUnichar *mKey;
-};
-
-
-class mozPersonalDictionary : public mozIPersonalDictionary, 
+class mozPersonalDictionary : public mozIPersonalDictionary,
                               public nsIObserver,
                               public nsSupportsWeakReference
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_MOZIPERSONALDICTIONARY
   NS_DECL_NSIOBSERVER
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozPersonalDictionary, mozIPersonalDictionary)
 
   mozPersonalDictionary();
   virtual ~mozPersonalDictionary();
 
   nsresult Init();
 
 protected:
   bool           mDirty;       /* has the dictionary been modified */
-  nsTHashtable<nsUniCharEntry> mDictionaryTable;
-  nsTHashtable<nsUniCharEntry> mIgnoreTable;
+  nsTHashtable<nsUnicharPtrHashKey> mDictionaryTable;
+  nsTHashtable<nsUnicharPtrHashKey> mIgnoreTable;
   nsCOMPtr<nsIUnicodeEncoder>  mEncoder; /*Encoder to use to compare with spellchecker word */
 };
 
 #endif
new file mode 100644
--- /dev/null
+++ b/gfx/ycbcr/QuellGccWarnings.patch
@@ -0,0 +1,40 @@
+diff --git a/gfx/ycbcr/yuv_convert.cpp b/gfx/ycbcr/yuv_convert.cpp
+--- a/gfx/ycbcr/yuv_convert.cpp
++++ b/gfx/ycbcr/yuv_convert.cpp
+@@ -337,16 +337,17 @@ NS_GFX_(void) ScaleYCbCrToRGB32(const ui
+                                          source_dx_uv >> kFractionBits);
+         }
+       }
+       else {
+         ScaleYUVToRGB32Row_C(y_ptr, u_ptr, v_ptr,
+                              dest_pixel, width, source_dx);
+       }
+ #else
++      (void)source_dx_uv;
+       ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
+                          dest_pixel, width, source_dx);
+ #endif
+     }
+   }
+   // MMX used for FastConvertYUVToRGB32Row and FilterRows requires emms.
+   if (has_mmx)
+     EMMS();
+diff --git a/gfx/ycbcr/yuv_row.h b/gfx/ycbcr/yuv_row.h
+--- a/gfx/ycbcr/yuv_row.h
++++ b/gfx/ycbcr/yuv_row.h
+@@ -129,14 +129,14 @@ extern SIMD_ALIGNED(int16 kCoefficientsR
+ #if defined(ARCH_CPU_X86) && !defined(ARCH_CPU_X86_64)
+ #if defined(_MSC_VER)
+ #define EMMS() __asm emms
+ #pragma warning(disable: 4799)
+ #else
+ #define EMMS() asm("emms")
+ #endif
+ #else
+-#define EMMS()
++#define EMMS() ((void)0)
+ #endif
+ 
+ }  // extern "C"
+ 
+ #endif  // MEDIA_BASE_YUV_ROW_H_
--- a/gfx/ycbcr/README
+++ b/gfx/ycbcr/README
@@ -20,8 +20,10 @@ convert.patch contains the following cha
   * Add YCbCr 4:4:4 support
   * Bug 619178 - Update CPU detection in yuv_convert to new SSE.h interface.
   * Bug 616778 - Split yuv_convert FilterRows vectorized code into separate files so it can
     be properly guarded with cpuid() calls.
 
 win64.patch: SSE2 optimization for Microsoft Visual C++ x64 version
 
 TypeFromSize.patch: Bug 656185 - Add a method to detect YUVType from plane sizes.
+
+QuellGccWarnings.patch: Bug 711895 - Avoid some GCC compilation warnings.
--- a/gfx/ycbcr/update.sh
+++ b/gfx/ycbcr/update.sh
@@ -4,8 +4,9 @@ cp $1/media/base/yuv_convert.cc yuv_conv
 cp $1/media/base/yuv_row.h .
 cp $1/media/base/yuv_row_table.cc yuv_row_table.cpp
 cp $1/media/base/yuv_row_posix.cc yuv_row_posix.cpp
 cp $1/media/base/yuv_row_win.cc yuv_row_win.cpp
 cp $1/media/base/yuv_row_posix.cc yuv_row_c.cpp
 patch -p3 <convert.patch
 patch -p3 <win64.patch
 patch -p3 <TypeFromSize.patch
+patch -p3 <QuellGccWarnings.patch
--- a/gfx/ycbcr/yuv_convert.cpp
+++ b/gfx/ycbcr/yuv_convert.cpp
@@ -337,16 +337,17 @@ NS_GFX_(void) ScaleYCbCrToRGB32(const ui
                                          source_dx_uv >> kFractionBits);
         }
       }
       else {
         ScaleYUVToRGB32Row_C(y_ptr, u_ptr, v_ptr,
                              dest_pixel, width, source_dx);
       }
 #else
+      (void)source_dx_uv;
       ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
                          dest_pixel, width, source_dx);
 #endif
     }
   }
   // MMX used for FastConvertYUVToRGB32Row and FilterRows requires emms.
   if (has_mmx)
     EMMS();
--- a/gfx/ycbcr/yuv_row.h
+++ b/gfx/ycbcr/yuv_row.h
@@ -129,14 +129,14 @@ extern SIMD_ALIGNED(int16 kCoefficientsR
 #if defined(ARCH_CPU_X86) && !defined(ARCH_CPU_X86_64)
 #if defined(_MSC_VER)
 #define EMMS() __asm emms
 #pragma warning(disable: 4799)
 #else
 #define EMMS() asm("emms")
 #endif
 #else
-#define EMMS()
+#define EMMS() ((void)0)
 #endif
 
 }  // extern "C"
 
 #endif  // MEDIA_BASE_YUV_ROW_H_
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1801,45 +1801,65 @@ if test "$GNU_CC"; then
     fi
     WARNINGS_AS_ERRORS='-Werror'
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-fPIC'
     ASFLAGS="$ASFLAGS -fPIC"
     _MOZ_RTTI_FLAGS_ON=-frtti
     _MOZ_RTTI_FLAGS_OFF=-fno-rtti
 
-    # Turn on GNU specific features
-    # -Wall - turn on all warnings
-    # -pedantic - make compiler warn about non-ANSI stuff, and
-    #             be a little bit stricter
-    # Warnings slamm took out for now (these were giving more noise than help):
-    # -Wbad-function-cast - warns when casting a function to a new return type
-    # -Wshadow - removed because it generates more noise than help --pete
-    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -W -Wno-unused -Wpointer-arith"
+    # Turn on GNU-specific warnings:
+    # -Wall - turn on a lot of warnings
+    # -pedantic - this is turned on below
+    # -Wpointer-arith - enabled with -pedantic, but good to have even if not
+    # -Wdeclaration-after-statement - MSVC doesn't like these
+    # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
+    #
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -Wpointer-arith -Wdeclaration-after-statement -Wempty-body"
+    
+    # Turn off the following warnings that -Wall/-pedantic turn on:
+    # -Woverlength-strings - we exceed the minimum maximum length all the time
+    #
+    _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-overlength-strings"
+
     if test -z "$INTEL_CC" -a -z "$CLANG_CC"; then
        # Don't use -Wcast-align with ICC or clang
        case "$CPU_ARCH" in
            # And don't use it on hppa, ia64, sparc, arm, since it's noisy there
            hppa | ia64 | sparc | arm)
            ;;
            *)
         _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wcast-align"
            ;;
        esac
     fi
 
     dnl Turn pedantic on but disable the warnings for long long
     _PEDANTIC=1
 
-    if test -z "$INTEL_CC"; then
-      _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -W"
-    fi
-
     _DEFINES_CFLAGS='-include $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT'
     _USE_CPP_INCLUDE_FLAG=1
+
+    AC_CACHE_CHECK(whether the compiler supports -Wtype-limits,
+                   ac_cc_has_wtype_limits,
+        [
+            AC_LANG_SAVE
+            AC_LANG_C
+            _SAVE_CFLAGS="$CFLAGS"
+            CFLAGS="$CFLAGS -Wtype-limits"
+            AC_TRY_COMPILE([],
+                           [return(0);],
+                           ac_cc_has_wtype_limits="yes",
+                           ac_cc_has_wtype_limits="no")
+            CFLAGS="$_SAVE_CFLAGS"
+            AC_LANG_RESTORE
+        ])
+    if test "$ac_cc_has_wtype_limits" = "yes"; then
+        _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
+    fi
 elif test "$SOLARIS_SUNPRO_CC"; then
     DSO_CFLAGS=''
     if test "$CPU_ARCH" = "sparc"; then
         # for Sun Studio on Solaris/SPARC
         DSO_PIC_CFLAGS='-xcode=pic32'
     else
         DSO_PIC_CFLAGS='-KPIC'
     fi
@@ -1855,18 +1875,31 @@ else
     fi
 
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-KPIC'
     _DEFINES_CFLAGS='$(ACDEFINES) -D_JS_CONFDEFS_H_ -DMOZILLA_CLIENT'
 fi
 
 if test "$GNU_CXX"; then
-    # Turn on GNU specific features
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor"
+    # Turn on GNU-specific warnings:
+    # -Wall - turn on a lot of warnings
+    # -pedantic - this is turned on below
+    # -Wpointer-arith - enabled with -pedantic, but good to have even if not
+    # -Woverloaded-virtual - ???
+    # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
+    #
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wempty-body"
+
+    # Turn off the following warnings that -Wall/-pedantic turn on:
+    # -Woverlength-strings - we exceed the minimum maximum length all the time
+    # -Wctor-dtor-privacy - ???
+    #
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-overlength-strings -Wno-ctor-dtor-privacy"
+
     if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
        # Don't use -Wcast-align with ICC or clang
        case "$CPU_ARCH" in
            # And don't use it on hppa, ia64, sparc, arm, since it's noisy there
            hppa | ia64 | sparc | arm)
            ;;
            *)
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wcast-align"
@@ -1957,16 +1990,34 @@ if test "$GNU_CXX"; then
                            ac_has_werror_return_type="no")
             CXXFLAGS="$_SAVE_CXXFLAGS"
             AC_LANG_RESTORE
         ])
     if test "$ac_has_werror_return_type" = "yes"; then
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
     fi
 
+    AC_CACHE_CHECK(whether the compiler supports -Wtype-limits,
+                   ac_has_wtype_limits,
+        [
+            AC_LANG_SAVE
+            AC_LANG_CPLUSPLUS
+            _SAVE_CXXFLAGS="$CXXFLAGS"
+            CXXFLAGS="$CXXFLAGS -Wtype-limits"
+            AC_TRY_COMPILE([],
+                           [return(0);],
+                           ac_has_wtype_limits="yes",
+                           ac_has_wtype_limits="no")
+            CXXFLAGS="$_SAVE_CXXFLAGS"
+            AC_LANG_RESTORE
+        ])
+    if test "$ac_has_wtype_limits" = "yes"; then
+        _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
+    fi
+
 else
     _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_JS_CONFDEFS_H_ $(ACDEFINES)'
 fi
 
 dnl gcc can come with its own linker so it is better to use the pass-thru calls
 dnl MKSHLIB_FORCE_ALL is used to force the linker to include all object
 dnl files present in an archive. MKSHLIB_UNFORCE_ALL reverts the linker to
 dnl normal behavior.
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -7329,18 +7329,20 @@ frontend::EmitTree(JSContext *cx, Byteco
       case PNK_VOID:
       case PNK_NOT:
       case PNK_BITNOT:
       case PNK_POS:
       case PNK_NEG:
         ok = EmitUnary(cx, bce, pn);
         break;
 
-      case PNK_INC:
-      case PNK_DEC:
+      case PNK_PREINCREMENT:
+      case PNK_PREDECREMENT:
+      case PNK_POSTINCREMENT:
+      case PNK_POSTDECREMENT:
         ok = EmitIncOrDec(cx, bce, pn);
         break;
 
       case PNK_DELETE:
         ok = EmitDelete(cx, bce, pn);
         break;
 
 #if JS_HAS_XML_SUPPORT
--- a/js/src/frontend/ParseMaps.h
+++ b/js/src/frontend/ParseMaps.h
@@ -36,16 +36,18 @@
  * 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 ***** */
 
 #ifndef ParseMaps_h__
 #define ParseMaps_h__
 
+#include "mozilla/Attributes.h"
+
 #include "ds/InlineMap.h"
 #include "js/HashTable.h"
 #include "js/Vector.h"
 
 namespace js {
 
 struct Definition;
 
@@ -262,18 +264,18 @@ template <> struct IsPodType<DefnOrHeade
 class AtomDecls
 {
     /* AtomDeclsIter needs to get at the DOHMap directly. */
     friend class AtomDeclsIter;
 
     JSContext   *cx;
     AtomDOHMap  *map;
 
-    AtomDecls(const AtomDecls &other);
-    void operator=(const AtomDecls &other);
+    AtomDecls(const AtomDecls &other) MOZ_DELETE;
+    void operator=(const AtomDecls &other) MOZ_DELETE;
 
     AtomDeclNode *allocNode(Definition *defn);
 
     /*
      * Fallibly return the value in |doh| as a node.
      * Update the defn currently occupying |doh| to a node if necessary.
      */
     AtomDeclNode *lastAsNode(DefnOrHeader *doh);
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -70,18 +70,20 @@ enum ParseNodeKind {
     PNK_BITAND,
     PNK_POS,
     PNK_NEG,
     PNK_ADD,
     PNK_SUB,
     PNK_STAR,
     PNK_DIV,
     PNK_MOD,
-    PNK_INC,
-    PNK_DEC,
+    PNK_PREINCREMENT,
+    PNK_POSTINCREMENT,
+    PNK_PREDECREMENT,
+    PNK_POSTDECREMENT,
     PNK_DOT,
     PNK_LB,
     PNK_RB,
     PNK_STATEMENTLIST,
     PNK_XMLCURLYEXPR,
     PNK_RC,
     PNK_LP,
     PNK_RP,
@@ -342,18 +344,20 @@ enum ParseNodeKind {
  * PNK_DIV,                 pn_op: JSOP_MUL, JSOP_DIV, JSOP_MOD
  * PNK_MOD
  * PNK_POS,     unary       pn_kid: UNARY expr
  * PNK_NEG
  * PNK_TYPEOF,  unary       pn_kid: UNARY expr
  * PNK_VOID,
  * PNK_NOT,
  * PNK_BITNOT
- * PNK_INC,     unary       pn_kid: MEMBER expr
- * PNK_DEC
+ * PNK_PREINCREMENT, unary  pn_kid: MEMBER expr
+ * PNK_POSTINCREMENT,
+ * PNK_PREDECREMENT,
+ * PNK_POSTDECREMENT
  * PNK_NEW      list        pn_head: list of ctor, arg1, arg2, ... argN
  *                          pn_count: 1 + N (where N is number of args)
  *                          ctor is a MEMBER expr
  * PNK_DELETE   unary       pn_kid: MEMBER expr
  * PNK_DOT,     name        pn_expr: MEMBER expr to left of .
  * PNK_DBLDOT               pn_atom: name to right of .
  * PNK_LB       binary      pn_left: MEMBER expr to left of [
  *                          pn_right: expr between [ and ]
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -4775,50 +4775,49 @@ Parser::assignExpr()
             JS_ASSERT(dn->isInitialized());
             dn->pn_pos.end = rhs->pn_pos.end;
         }
     }
 
     return ParseNode::newBinaryOrAppend(kind, op, lhs, rhs, tc);
 }
 
-static ParseNode *
+static bool
 SetLvalKid(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, ParseNode *kid,
            const char *name)
 {
     if (!kid->isKind(PNK_NAME) &&
         !kid->isKind(PNK_DOT) &&
         (!kid->isKind(PNK_LP) ||
          (!kid->isOp(JSOP_CALL) && !kid->isOp(JSOP_EVAL) &&
           !kid->isOp(JSOP_FUNCALL) && !kid->isOp(JSOP_FUNAPPLY))) &&
 #if JS_HAS_XML_SUPPORT
         !kid->isKind(PNK_XMLUNARY) &&
 #endif
         !kid->isKind(PNK_LB))
     {
         ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_OPERAND, name);
-        return NULL;
+        return false;
     }
     if (!CheckStrictAssignment(cx, tc, kid))
-        return NULL;
+        return false;
     pn->pn_kid = kid;
-    return kid;
+    return true;
 }
 
 static const char incop_name_str[][10] = {"increment", "decrement"};
 
 static JSBool
 SetIncOpKid(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, ParseNode *kid,
-            TokenKind tt, JSBool preorder)
+            TokenKind tt, bool preorder)
 {
     JSOp op;
 
-    kid = SetLvalKid(cx, ts, tc, pn, kid, incop_name_str[tt == TOK_DEC]);
-    if (!kid)
-        return JS_FALSE;
+    if (!SetLvalKid(cx, ts, tc, pn, kid, incop_name_str[tt == TOK_DEC]))
+        return false;
     switch (kid->getKind()) {
       case PNK_NAME:
         op = (tt == TOK_INC)
              ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC)
              : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC);
         NoteLValue(cx, kid, tc);
         break;
 
@@ -4880,23 +4879,23 @@ Parser::unaryExpr()
         return unaryOpExpr(PNK_BITNOT, JSOP_BITNOT);
       case TOK_PLUS:
         return unaryOpExpr(PNK_POS, JSOP_POS);
       case TOK_MINUS:
         return unaryOpExpr(PNK_NEG, JSOP_NEG);
 
       case TOK_INC:
       case TOK_DEC:
-        pn = UnaryNode::create((tt == TOK_INC) ? PNK_INC : PNK_DEC, tc);
+        pn = UnaryNode::create((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT, tc);
         if (!pn)
             return NULL;
         pn2 = memberExpr(JS_TRUE);
         if (!pn2)
             return NULL;
-        if (!SetIncOpKid(context, &tokenStream, tc, pn, pn2, tt, JS_TRUE))
+        if (!SetIncOpKid(context, &tokenStream, tc, pn, pn2, tt, true))
             return NULL;
         pn->pn_pos.end = pn2->pn_pos.end;
         break;
 
       case TOK_DELETE:
       {
         pn = UnaryNode::create(PNK_DELETE, tc);
         if (!pn)
@@ -4949,21 +4948,21 @@ Parser::unaryExpr()
         pn = memberExpr(JS_TRUE);
         if (!pn)
             return NULL;
 
         /* Don't look across a newline boundary for a postfix incop. */
         if (tokenStream.onCurrentLine(pn->pn_pos)) {
             tt = tokenStream.peekTokenSameLine(TSF_OPERAND);
             if (tt == TOK_INC || tt == TOK_DEC) {
-                (void) tokenStream.getToken();
-                pn2 = UnaryNode::create((tt == TOK_INC) ? PNK_INC : PNK_DEC, tc);
+                tokenStream.consumeKnownToken(tt);
+                pn2 = UnaryNode::create((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, tc);
                 if (!pn2)
                     return NULL;
-                if (!SetIncOpKid(context, &tokenStream, tc, pn2, pn, tt, JS_FALSE))
+                if (!SetIncOpKid(context, &tokenStream, tc, pn2, pn, tt, false))
                     return NULL;
                 pn2->pn_pos.begin = pn->pn_pos.begin;
                 pn = pn2;
             }
         }
         break;
     }
     return pn;
@@ -6816,23 +6815,32 @@ Parser::primaryExpr(TokenKind tt, JSBool
 
                     pn->pn_xflags |= PNX_NONCONST;
 
                     /* NB: Getter function in { get x(){} } is unnamed. */
                     pn2 = functionDef(NULL, op == JSOP_GETTER ? Getter : Setter, Expression);
                     pn2 = ParseNode::newBinaryOrAppend(PNK_COLON, op, pn3, pn2, tc);
                     goto skip;
                 }
-              case TOK_STRING:
+              case TOK_STRING: {
                 atom = tokenStream.currentToken().atom();
-                pn3 = NullaryNode::create(PNK_STRING, tc);
-                if (!pn3)
-                    return NULL;
-                pn3->pn_atom = atom;
+                uint32_t index;
+                if (atom->isIndex(&index)) {
+                    pn3 = NullaryNode::create(PNK_NUMBER, tc);
+                    if (!pn3)
+                        return NULL;
+                    pn3->pn_dval = index;
+                } else {
+                    pn3 = NullaryNode::create(PNK_STRING, tc);
+                    if (!pn3)
+                        return NULL;
+                    pn3->pn_atom = atom;
+                }
                 break;
+              }
               case TOK_RC:
                 goto end_obj_init;
               default:
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_PROP_ID);
                 return NULL;
             }
 
             op = JSOP_INITPROP;
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -100,16 +100,23 @@ HeapValue::~HeapValue()
 inline void
 HeapValue::init(const Value &v)
 {
     value = v;
     post();
 }
 
 inline void
+HeapValue::init(JSCompartment *comp, const Value &v)
+{
+    value = v;
+    post(comp);
+}
+
+inline void
 HeapValue::writeBarrierPre(const Value &value)
 {
 #ifdef JSGC_INCREMENTAL
     if (value.isMarkable()) {
         js::gc::Cell *cell = (js::gc::Cell *)value.toGCThing();
         writeBarrierPre(cell->compartment(), value);
     }
 #endif
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -297,16 +297,17 @@ class HeapValue
   public:
     explicit HeapValue() : value(UndefinedValue()) {}
     explicit inline HeapValue(const Value &v);
     explicit inline HeapValue(const HeapValue &v);
 
     inline ~HeapValue();
 
     inline void init(const Value &v);
+    inline void init(JSCompartment *comp, const Value &v);
 
     inline HeapValue &operator=(const Value &v);
     inline HeapValue &operator=(const HeapValue &v);
 
     /*
      * This is a faster version of operator=. Normally, operator= has to
      * determine the compartment of the value before it can decide whether to do
      * the barrier. If you already know the compartment, it's faster to pass it
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -400,20 +400,33 @@ DoGetElement(JSContext *cx, JSObject *ob
     *hole = !present;
     if (*hole)
         vp->setUndefined();
 
     return true;
 }
 
 template<typename IndexType>
+static void
+AssertGreaterThanZero(IndexType index)
+{
+    JS_ASSERT(index >= 0);
+}
+
+template<>
+void
+AssertGreaterThanZero(jsuint index)
+{
+}
+
+template<typename IndexType>
 static JSBool
 GetElement(JSContext *cx, JSObject *obj, IndexType index, JSBool *hole, Value *vp)
 {
-    JS_ASSERT(index >= 0);
+    AssertGreaterThanZero(index);
     if (obj->isDenseArray() && index < obj->getDenseArrayInitializedLength() &&
         !(*vp = obj->getDenseArrayElement(uint32_t(index))).isMagic(JS_ARRAY_HOLE)) {
         *hole = JS_FALSE;
         return JS_TRUE;
     }
     if (obj->isArguments()) {
         if (obj->asArguments()->getElement(uint32_t(index), vp)) {
             *hole = JS_FALSE;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -33,21 +33,23 @@
  * 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 ***** */
 
+/* JS execution context. */
+
 #ifndef jscntxt_h___
 #define jscntxt_h___
-/*
- * JS execution context.
- */
+
+#include "mozilla/Attributes.h"
+
 #include <string.h>
 
 #include "jsfriendapi.h"
 #include "jsprvtd.h"
 #include "jsatom.h"
 #include "jsclist.h"
 #include "jsdhash.h"
 #include "jsgc.h"
@@ -1401,20 +1403,19 @@ class AutoGCRooter {
         ID =          -11, /* js::AutoIdRooter */
         VALVECTOR =   -12, /* js::AutoValueVector */
         DESCRIPTOR =  -13, /* js::AutoPropertyDescriptorRooter */
         STRING =      -14, /* js::AutoStringRooter */
         IDVECTOR =    -15, /* js::AutoIdVector */
         OBJVECTOR =   -16  /* js::AutoObjectVector */
     };
 
-    private:
-    /* No copy or assignment semantics. */
-    AutoGCRooter(AutoGCRooter &ida);
-    void operator=(AutoGCRooter &ida);
+  private:
+    AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE;
+    void operator=(AutoGCRooter &ida) MOZ_DELETE;
 };
 
 /* FIXME(bug 332648): Move this into a public header. */
 class AutoValueRooter : private AutoGCRooter
 {
   public:
     explicit AutoValueRooter(JSContext *cx
                              JS_GUARD_OBJECT_NOTIFIER_PARAM)
@@ -1613,19 +1614,18 @@ class AutoIdArray : private AutoGCRooter
 
   protected:
     inline void trace(JSTracer *trc);
 
   private:
     JSIdArray * idArray;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 
-    /* No copy or assignment semantics. */
-    AutoIdArray(AutoIdArray &ida);
-    void operator=(AutoIdArray &ida);
+    AutoIdArray(AutoIdArray &ida) MOZ_DELETE;
+    void operator=(AutoIdArray &ida) MOZ_DELETE;
 };
 
 /* The auto-root for enumeration object and its state. */
 class AutoEnumStateRooter : private AutoGCRooter
 {
   public:
     AutoEnumStateRooter(JSContext *cx, JSObject *obj
                         JS_GUARD_OBJECT_NOTIFIER_PARAM)
@@ -1792,17 +1792,18 @@ class AutoKeepAtoms {
     ~AutoKeepAtoms() { JS_UNKEEP_ATOMS(rt); }
 };
 
 class AutoReleasePtr {
     JSContext   *cx;
     void        *ptr;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 
-    AutoReleasePtr operator=(const AutoReleasePtr &other);
+    AutoReleasePtr(const AutoReleasePtr &other) MOZ_DELETE;
+    AutoReleasePtr operator=(const AutoReleasePtr &other) MOZ_DELETE;
 
   public:
     explicit AutoReleasePtr(JSContext *cx, void *ptr
                             JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : cx(cx), ptr(ptr)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
@@ -1812,17 +1813,18 @@ class AutoReleasePtr {
 /*
  * FIXME: bug 602774: cleaner API for AutoReleaseNullablePtr
  */
 class AutoReleaseNullablePtr {
     JSContext   *cx;
     void        *ptr;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 
-    AutoReleaseNullablePtr operator=(const AutoReleaseNullablePtr &other);
+    AutoReleaseNullablePtr(const AutoReleaseNullablePtr &other) MOZ_DELETE;
+    AutoReleaseNullablePtr operator=(const AutoReleaseNullablePtr &other) MOZ_DELETE;
 
   public:
     explicit AutoReleaseNullablePtr(JSContext *cx, void *ptr
                                     JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : cx(cx), ptr(ptr)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -251,28 +251,28 @@ CopyErrorReport(JSContext *cx, JSErrorRe
 
     /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */
     copy->flags = report->flags;
 
 #undef JS_CHARS_SIZE
     return copy;
 }
 
-static jsval *
+static HeapValue *
 GetStackTraceValueBuffer(JSExnPrivate *priv)
 {
     /*
      * We use extra memory after JSExnPrivateInfo.stackElems to store jsvals
      * that helps to produce more informative stack traces. The following
      * assert allows us to assume that no gap after stackElems is necessary to
      * align the buffer properly.
      */
     JS_STATIC_ASSERT(sizeof(JSStackTraceElem) % sizeof(jsval) == 0);
 
-    return (jsval *)(priv->stackElems + priv->stackDepth);
+    return reinterpret_cast<HeapValue *>(priv->stackElems + priv->stackDepth);
 }
 
 struct SuppressErrorsGuard
 {
     JSContext *cx;
     JSErrorReporter prevReporter;
     JSExceptionState *prevState;
 
@@ -354,17 +354,17 @@ InitExnPrivate(JSContext *cx, JSObject *
         }
     }
 
     /* Do not need overflow check: the vm stack is already bigger. */
     JS_STATIC_ASSERT(sizeof(JSStackTraceElem) <= sizeof(StackFrame));
 
     size_t nbytes = offsetof(JSExnPrivate, stackElems) +
                     frames.length() * sizeof(JSStackTraceElem) +
-                    values.length() * sizeof(Value);
+                    values.length() * sizeof(HeapValue);
 
     JSExnPrivate *priv = (JSExnPrivate *)cx->malloc_(nbytes);
     if (!priv)
         return false;
 
     /* Initialize to zero so that write barriers don't witness undefined values. */
     memset(priv, 0, nbytes);
 
@@ -386,21 +386,22 @@ InitExnPrivate(JSContext *cx, JSObject *
 
     priv->message.init(message);
     priv->filename.init(filename);
     priv->lineno = lineno;
     priv->stackDepth = frames.length();
     priv->exnType = exnType;
 
     JSStackTraceElem *framesDest = priv->stackElems;
-    Value *valuesDest = reinterpret_cast<Value *>(framesDest + frames.length());
+    HeapValue *valuesDest = reinterpret_cast<HeapValue *>(framesDest + frames.length());
     JS_ASSERT(valuesDest == GetStackTraceValueBuffer(priv));
 
     PodCopy(framesDest, frames.begin(), frames.length());
-    PodCopy(valuesDest, values.begin(), values.length());
+    for (size_t i = 0; i < values.length(); ++i)
+        valuesDest[i].init(cx->compartment, values[i]);
 
     SetExnPrivate(cx, exnObject, priv);
     return true;
 }
 
 static inline JSExnPrivate *
 GetExnPrivate(JSObject *obj)
 {
@@ -409,17 +410,17 @@ GetExnPrivate(JSObject *obj)
 }
 
 static void
 exn_trace(JSTracer *trc, JSObject *obj)
 {
     JSExnPrivate *priv;
     JSStackTraceElem *elem;
     size_t vcount, i;
-    jsval *vp, v;
+    HeapValue *vp;
 
     priv = GetExnPrivate(obj);
     if (priv) {
         if (priv->message)
             MarkString(trc, priv->message, "exception message");
         if (priv->filename)
             MarkString(trc, priv->filename, "exception filename");
 
@@ -428,19 +429,17 @@ exn_trace(JSTracer *trc, JSObject *obj)
             if (elem->funName)
                 MarkString(trc, elem->funName, "stack trace function name");
             if (IS_GC_MARKING_TRACER(trc) && elem->filename)
                 js_MarkScriptFilename(elem->filename);
             vcount += elem->argc;
         }
         vp = GetStackTraceValueBuffer(priv);
         for (i = 0; i != vcount; ++i, ++vp) {
-            /* This value is read-only, so it's okay for it to be Unbarriered. */
-            v = *vp;
-            MarkValueUnbarriered(trc, v, "stack trace argument");
+            MarkValue(trc, *vp, "stack trace argument");
         }
     }
 }
 
 /* NB: An error object's private must be set through this function. */
 static void
 SetExnPrivate(JSContext *cx, JSObject *exnObject, JSExnPrivate *priv)
 {
@@ -600,17 +599,17 @@ ValueToShortSource(JSContext *cx, const 
 }
 
 static JSString *
 StackTraceToString(JSContext *cx, JSExnPrivate *priv)
 {
     jschar *stackbuf;
     size_t stacklen, stackmax;
     JSStackTraceElem *elem, *endElem;
-    jsval *values;
+    HeapValue *values;
     size_t i;
     JSString *str;
     const char *cp;
     char ulnbuf[11];
 
     /* After this point, failing control flow must goto bad. */
     stackbuf = NULL;
     stacklen = stackmax = 0;
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1730,17 +1730,17 @@ JSFunction::initBoundFunction(JSContext 
         return false;
 
     if (!setSlotSpan(cx, BOUND_FUNCTION_RESERVED_SLOTS + argslen))
         return false;
 
     setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
     setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
 
-    copySlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen, false);
+    initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen);
 
     return true;
 }
 
 inline JSObject *
 JSFunction::getBoundFunctionTarget() const
 {
     JS_ASSERT(isFunction());
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -33,31 +33,32 @@
  * 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 ***** */
 
+/* JS Mark-and-Sweep Garbage Collector. */
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Util.h"
+
 /*
- * JS Mark-and-Sweep Garbage Collector.
- *
  * This GC allocates fixed-sized things with sizes up to GC_NBYTES_MAX (see
  * jsgc.h). It allocates from a special GC arena pool with each arena allocated
  * using malloc. It uses an ideally parallel array of flag bytes to hold the
  * mark bit, finalizer type index, etc.
  *
  * XXX swizzle page to freelist for better locality of reference
  */
 #include <math.h>
 #include <string.h>     /* for memset used when DEBUG */
 
-#include "mozilla/Util.h"
-
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsclist.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
@@ -468,79 +469,57 @@ ChunkPool::get(JSRuntime *rt)
         rt->gcHelperThread.startBackgroundAllocationIfIdle();
 #endif
 
     return chunk;
 }
 
 /* Must be called either during the GC or with the GC lock taken. */
 inline void
-ChunkPool::put(JSRuntime *rt, Chunk *chunk)
+ChunkPool::put(Chunk *chunk)
 {
-    JS_ASSERT(this == &rt->gcChunkPool);
-
-    size_t initialAge = 0;
-#ifdef JS_THREADSAFE
-    /*
-     * When we have not yet started the background finalization, we must keep
-     * empty chunks until we are done with all the sweeping and finalization
-     * that cannot be done in the background even if shouldShrink() is true.
-     * This way we can safely call IsAboutToBeFinalized and Cell::isMarked for
-     * finalized GC things in empty chunks. So we only release the chunk if we
-     * are called from the background thread.
-     */
-    if (rt->gcHelperThread.sweeping()) {
-        if (rt->gcHelperThread.shouldShrink()) {
-            Chunk::release(rt, chunk);
-            return;
-        }
-
-        /*
-         * Set the age to one as we expire chunks early during the background
-         * sweep so this chunk already survived one GC cycle.
-         */
-        initialAge = 1;
-    }
-#endif
-
-    chunk->info.age = initialAge;
+    chunk->info.age = 0;
     chunk->info.next = emptyChunkListHead;
     emptyChunkListHead = chunk;
     emptyCount++;
 }
 
 /* Must be called either during the GC or with the GC lock taken. */
-void
+Chunk *
 ChunkPool::expire(JSRuntime *rt, bool releaseAll)
 {
     JS_ASSERT(this == &rt->gcChunkPool);
 
     /*
      * Return old empty chunks to the system while preserving the order of
      * other chunks in the list. This way, if the GC runs several times
      * without emptying the list, the older chunks will stay at the tail
      * and are more likely to reach the max age.
      */
+    Chunk *freeList = NULL;
     for (Chunk **chunkp = &emptyChunkListHead; *chunkp; ) {
         JS_ASSERT(emptyCount);
         Chunk *chunk = *chunkp;
         JS_ASSERT(chunk->unused());
         JS_ASSERT(!rt->gcChunkSet.has(chunk));
         JS_ASSERT(chunk->info.age <= MAX_EMPTY_CHUNK_AGE);
         if (releaseAll || chunk->info.age == MAX_EMPTY_CHUNK_AGE) {
             *chunkp = chunk->info.next;
             --emptyCount;
-            Chunk::release(rt, chunk);
+            chunk->prepareToBeFreed(rt);
+            chunk->info.next = freeList;
+            freeList = chunk;
         } else {
             /* Keep the chunk but increase its age. */
             ++chunk->info.age;
             chunkp = &chunk->info.next;
         }
     }
     JS_ASSERT_IF(releaseAll, !emptyCount);
+    return freeList;
 }
 
 JS_FRIEND_API(int64_t)
 ChunkPool::countCleanDecommittedArenas(JSRuntime *rt)
 {
     JS_ASSERT(this == &rt->gcChunkPool);
 
     int64_t numDecommitted = 0;
@@ -565,20 +544,44 @@ Chunk::allocate(JSRuntime *rt)
     return chunk;
 }
 
 /* Must be called with the GC lock taken. */
 /* static */ inline void
 Chunk::release(JSRuntime *rt, Chunk *chunk)
 {
     JS_ASSERT(chunk);
-    JS_ASSERT(rt->gcNumArenasFreeCommitted >= chunk->info.numArenasFreeCommitted);
-    rt->gcNumArenasFreeCommitted -= chunk->info.numArenasFreeCommitted;
+    chunk->prepareToBeFreed(rt);
+    FreeChunk(chunk);
+}
+
+static void
+FreeChunkList(Chunk *chunkListHead)
+{
+    while (Chunk *chunk = chunkListHead) {
+        JS_ASSERT(!chunk->info.numArenasFreeCommitted);
+        chunkListHead = chunk->info.next;
+        FreeChunk(chunk);
+    }
+}
+
+inline void
+Chunk::prepareToBeFreed(JSRuntime *rt)
+{
+    JS_ASSERT(rt->gcNumArenasFreeCommitted >= info.numArenasFreeCommitted);
+    rt->gcNumArenasFreeCommitted -= info.numArenasFreeCommitted;
     rt->gcStats.count(gcstats::STAT_DESTROY_CHUNK);
-    FreeChunk(chunk);
+
+#ifdef DEBUG
+    /*
+     * Let FreeChunkList detect a missing prepareToBeFreed call before it
+     * frees chunk.
+     */
+    info.numArenasFreeCommitted = 0;
+#endif
 }
 
 void
 Chunk::init()
 {
     JS_POISON(this, JS_FREE_PATTERN, ChunkSize);
 
     /*
@@ -718,16 +721,27 @@ Chunk::allocateArena(JSCompartment *comp
     JS_ATOMIC_ADD(&rt->gcBytes, ArenaSize);
     JS_ATOMIC_ADD(&comp->gcBytes, ArenaSize);
     if (comp->gcBytes >= comp->gcTriggerBytes)
         TriggerCompartmentGC(comp, gcstats::ALLOCTRIGGER);
 
     return aheader;
 }
 
+inline void
+Chunk::addArenaToFreeList(JSRuntime *rt, ArenaHeader *aheader)
+{
+    JS_ASSERT(!aheader->allocated());
+    aheader->next = info.freeArenasHead;
+    info.freeArenasHead = aheader;
+    ++info.numArenasFreeCommitted;
+    ++info.numArenasFree;
+    ++rt->gcNumArenasFreeCommitted;
+}
+
 void
 Chunk::releaseArena(ArenaHeader *aheader)
 {
     JS_ASSERT(aheader->allocated());
     JS_ASSERT(!aheader->hasDelayedMarking);
     JSCompartment *comp = aheader->compartment;
     JSRuntime *rt = comp->rt;
 #ifdef JS_THREADSAFE
@@ -744,32 +758,28 @@ Chunk::releaseArena(ArenaHeader *aheader
         rt->reduceGCTriggerBytes(GC_HEAP_GROWTH_FACTOR * ArenaSize);
         comp->reduceGCTriggerBytes(GC_HEAP_GROWTH_FACTOR * ArenaSize);
     }
 #endif
     JS_ATOMIC_ADD(&rt->gcBytes, -int32_t(ArenaSize));
     JS_ATOMIC_ADD(&comp->gcBytes, -int32_t(ArenaSize));
 
     aheader->setAsNotAllocated();
-    aheader->next = info.freeArenasHead;
-    info.freeArenasHead = aheader;
-    ++info.numArenasFreeCommitted;
-    ++info.numArenasFree;
-    ++rt->gcNumArenasFreeCommitted;
+    addArenaToFreeList(rt, aheader);
 
     if (info.numArenasFree == 1) {
         JS_ASSERT(!info.prevp);
         JS_ASSERT(!info.next);
         addToAvailableList(comp);
     } else if (!unused()) {
         JS_ASSERT(info.prevp);
     } else {
         rt->gcChunkSet.remove(this);
         removeFromAvailableList();
-        rt->gcChunkPool.put(rt, this);
+        rt->gcChunkPool.put(this);
     }
 }
 
 } /* namespace gc */
 } /* namespace js */
 
 /* The caller must hold the GC lock. */
 static Chunk *
@@ -1167,17 +1177,17 @@ js_FinishGC(JSRuntime *rt)
 #ifdef JS_THREADSAFE
     rt->gcHelperThread.finish();
 #endif
 
     /*
      * Finish the pool after the background thread stops in case it was doing
      * the background sweeping.
      */
-    rt->gcChunkPool.expire(rt, true);
+    FreeChunkList(rt->gcChunkPool.expire(rt, true));
 
 #ifdef DEBUG
     if (!rt->gcRootsHash.empty())
         CheckLeakedRoots(rt);
 #endif
     rt->gcRootsHash.clear();
     rt->gcLocksHash.clear();
 }
@@ -1327,17 +1337,17 @@ JSRuntime::setGCLastBytes(size_t lastByt
     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_t amount) {
     JS_ASSERT(amount > 0);
-    JS_ASSERT(gcTriggerBytes - amount >= 0);
+    JS_ASSERT(gcTriggerBytes >= amount);
     if (gcTriggerBytes - amount < GC_ALLOCATION_THRESHOLD * GC_HEAP_GROWTH_FACTOR)
         return;
     gcTriggerBytes -= amount;
 }
 
 void
 JSCompartment::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
 {
@@ -1346,17 +1356,17 @@ JSCompartment::setGCLastBytes(size_t las
     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_t amount) {
     JS_ASSERT(amount > 0);
-    JS_ASSERT(gcTriggerBytes - amount >= 0);
+    JS_ASSERT(gcTriggerBytes >= amount);
     if (gcTriggerBytes - amount < GC_ALLOCATION_THRESHOLD * GC_HEAP_GROWTH_FACTOR)
         return;
     gcTriggerBytes -= amount;
 }
 
 namespace js {
 namespace gc {
 
@@ -2190,22 +2200,109 @@ MaybeGC(JSContext *cx)
         {
             js_GC(cx, NULL, GC_SHRINK, gcstats::MAYBEGC);
         } else {
             rt->gcNextFullGCTime = now + GC_IDLE_FULL_SPAN;
         }
     }
 }
 
-} /* namespace js */
+static void
+DecommitArenasFromAvailableList(JSRuntime *rt, Chunk **availableListHeadp)
+{
+    Chunk *chunk = *availableListHeadp;
+    if (!chunk)
+        return;
+
+    /*
+     * Decommit is expensive so we avoid holding the GC lock while calling it.
+     *
+     * We decommit from the tail of the list to minimize interference with the
+     * main thread that may start to allocate things at this point.
+     */
+    JS_ASSERT(chunk->info.prevp == availableListHeadp);
+    while (Chunk *next = chunk->info.next) {
+        JS_ASSERT(next->info.prevp == &chunk->info.next);
+        chunk = next;
+    }
+
+    for (;;) {
+        while (chunk->info.numArenasFreeCommitted != 0) {
+            /*
+             * The arena that is been decommitted outside the GC lock must not
+             * be available for allocations either via the free list or via
+             * the decommittedArenas bitmap. For that we just fetch the arena
+             * from the free list before the decommit and then mark it as free
+             * and decommitted when we retake the GC lock.
+             *
+             * We also must make sure that the aheader is not accessed again
+             * after we decommit the arena.
+             */
+            ArenaHeader *aheader = chunk->fetchNextFreeArena(rt);
+            size_t arenaIndex = Chunk::arenaIndex(aheader->arenaAddress());
+            bool ok;
+            {
+                AutoUnlockGC unlock(rt);
+                ok = DecommitMemory(aheader->getArena(), ArenaSize);
+            }
+
+            if (ok) {
+                ++chunk->info.numArenasFree;
+                chunk->decommittedArenas.set(arenaIndex);
+            } else {
+                chunk->addArenaToFreeList(rt, aheader);
+            }
+
+            if (rt->gcChunkAllocationSinceLastGC) {
+                /*
+                 * The allocator thread has started to get new chunks. We should stop
+                 * to avoid decommitting arenas in just allocated chunks.
+                 */
+                return;
+            }
+        }
+
+        /*
+         * prevp becomes null when the allocator thread consumed all chunks from
+         * the available list.
+         */
+        JS_ASSERT_IF(chunk->info.prevp, *chunk->info.prevp == chunk);
+        if (chunk->info.prevp == availableListHeadp || !chunk->info.prevp)
+            break;
+
+        /*
+         * prevp exists and is not the list head. It must point to the next
+         * field of the previous chunk.
+         */
+        chunk = chunk->getPrevious();
+    }
+}
+
+static void
+DecommitArenas(JSRuntime *rt)
+{
+    DecommitArenasFromAvailableList(rt, &rt->gcSystemAvailableChunkListHead);
+    DecommitArenasFromAvailableList(rt, &rt->gcUserAvailableChunkListHead);
+}
+
+/* Must be called with the GC lock taken. */
+static void
+ExpireChunksAndArenas(JSRuntime *rt, bool shouldShrink)
+{
+    if (Chunk *toFree = rt->gcChunkPool.expire(rt, shouldShrink)) {
+        AutoUnlockGC unlock(rt);
+        FreeChunkList(toFree);
+    }
+
+    if (shouldShrink)
+        DecommitArenas(rt);
+}
 
 #ifdef JS_THREADSAFE
 
-namespace js {
-
 bool
 GCHelperThread::init()
 {
     if (!(wakeup = PR_NewCondVar(rt->gcLock)))
         return false;
     if (!(done = PR_NewCondVar(rt->gcLock)))
         return false;
 
@@ -2281,17 +2378,17 @@ GCHelperThread::threadLoop()
                     chunk = Chunk::allocate(rt);
                 }
 
                 /* OOM stops the background allocation. */
                 if (!chunk)
                     break;
                 JS_ASSERT(chunk->info.numArenasFreeCommitted == ArenasPerChunk);
                 rt->gcNumArenasFreeCommitted += ArenasPerChunk;
-                rt->gcChunkPool.put(rt, chunk);
+                rt->gcChunkPool.put(chunk);
             } while (state == ALLOCATING && rt->gcChunkPool.wantBackgroundAllocation(rt));
             if (state == ALLOCATING)
                 state = IDLE;
             break;
           case CANCEL_ALLOCATION:
             state = IDLE;
             PR_NotifyAllCondVar(done);
             break;
@@ -2370,105 +2467,66 @@ GCHelperThread::replenishAndFreeLater(vo
 }
 
 /* Must be called with the GC lock taken. */
 void
 GCHelperThread::doSweep()
 {
     JS_ASSERT(context);
 
-    /*
-     * Expire the chunks released during the GC so they will be available to
-     * the rest of the system immediately.
-     */
-    rt->gcChunkPool.expire(rt, shouldShrink());
-
-    AutoUnlockGC unlock(rt);
-
-    /*
-     * We must finalize in the insert order, see comments in
-     * finalizeObjects.
-     */
-    for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i)
-        ArenaLists::backgroundFinalize(context, *i);
-    finalizeVector.resize(0);
-
-    context = NULL;
-
-    if (freeCursor) {
-        void **array = freeCursorEnd - FREE_ARRAY_LENGTH;
-        freeElementsAndArray(array, freeCursor);
-        freeCursor = freeCursorEnd = NULL;
-    } else {
-        JS_ASSERT(!freeCursorEnd);
+    {
+        AutoUnlockGC unlock(rt);
+
+        /*
+         * We must finalize in the insert order, see comments in
+         * finalizeObjects.
+         */
+        for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i)
+            ArenaLists::backgroundFinalize(context, *i);
+        finalizeVector.resize(0);
+
+        context = NULL;
+
+        if (freeCursor) {
+            void **array = freeCursorEnd - FREE_ARRAY_LENGTH;
+            freeElementsAndArray(array, freeCursor);
+            freeCursor = freeCursorEnd = NULL;
+        } else {
+            JS_ASSERT(!freeCursorEnd);
+        }
+        for (void ***iter = freeVector.begin(); iter != freeVector.end(); ++iter) {
+            void **array = *iter;
+            freeElementsAndArray(array, array + FREE_ARRAY_LENGTH);
+        }
+        freeVector.resize(0);
     }
-    for (void ***iter = freeVector.begin(); iter != freeVector.end(); ++iter) {
-        void **array = *iter;
-        freeElementsAndArray(array, array + FREE_ARRAY_LENGTH);
-    }
-    freeVector.resize(0);
+
+    ExpireChunksAndArenas(rt, shouldShrink());
 }
 
+#endif /* JS_THREADSAFE */
+
 } /* namespace js */
 
-#endif /* JS_THREADSAFE */
-
 static bool
 ReleaseObservedTypes(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
 
     bool releaseTypes = false;
     int64_t now = PRMJ_Now();
     if (now >= rt->gcJitReleaseTime) {
         releaseTypes = true;
         rt->gcJitReleaseTime = now + JIT_SCRIPT_RELEASE_TYPES_INTERVAL;
     }
 
     return releaseTypes;
 }
 
 static void
-DecommitFreePages(JSContext *cx)
-{
-    JSRuntime *rt = cx->runtime;
-
-    for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
-        Chunk *chunk = r.front();
-        ArenaHeader *aheader = chunk->info.freeArenasHead;
-
-        /*
-         * In the non-failure case, the list will be gone at the end of
-         * the loop. In the case where we fail, we relink all failed
-         * decommits into a new list on freeArenasHead.
-         */
-        chunk->info.freeArenasHead = NULL;
-
-        while (aheader) {
-            /* Store aside everything we will need after decommit. */
-            ArenaHeader *next = aheader->next;
-
-            bool success = DecommitMemory(aheader, ArenaSize);
-            if (!success) {
-                aheader->next = chunk->info.freeArenasHead;
-                chunk->info.freeArenasHead = aheader;
-                continue;
-            }
-
-            size_t arenaIndex = Chunk::arenaIndex(aheader->arenaAddress());
-            chunk->decommittedArenas.set(arenaIndex);
-            --chunk->info.numArenasFreeCommitted;
-            --rt->gcNumArenasFreeCommitted;
-
-            aheader = next;
-        }
-    }
-}
-
-static void
 SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
 {
     JSRuntime *rt = cx->runtime;
     JSCompartmentCallback callback = rt->compartmentCallback;
 
     /* Skip the atomsCompartment. */
     JSCompartment **read = rt->compartments.begin() + 1;
     JSCompartment **end = rt->compartments.end();
@@ -2651,21 +2709,18 @@ SweepPhase(JSContext *cx, GCMarker *gcma
             SweepCompartments(cx, gckind);
 
 #ifndef JS_THREADSAFE
         /*
          * Destroy arenas after we finished the sweeping so finalizers can safely
          * use IsAboutToBeFinalized().
          * This is done on the GCHelperThread if JS_THREADSAFE is defined.
          */
-        rt->gcChunkPool.expire(rt, gckind == GC_SHRINK);
+        ExpireChunksAndArenas(rt, gckind == GC_SHRINK);
 #endif
-
-        if (gckind == GC_SHRINK)
-            DecommitFreePages(cx);
     }
 
     {
         gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_XPCONNECT);
         if (rt->gcCallback)
             (void) rt->gcCallback(cx, JSGC_FINALIZE_END);
     }
 }
@@ -2777,19 +2832,18 @@ LetOtherGCFinish(JSContext *cx)
 class AutoGCSession {
   public:
     explicit AutoGCSession(JSContext *cx);
     ~AutoGCSession();
 
   private:
     JSContext   *context;
 
-    /* Disable copy constructor or assignments */
-    AutoGCSession(const AutoGCSession&);
-    void operator=(const AutoGCSession&);
+    AutoGCSession(const AutoGCSession&) MOZ_DELETE;
+    void operator=(const AutoGCSession&) MOZ_DELETE;
 };
 
 /*
  * Start a new GC session. Together with LetOtherGCFinish this function
  * contains the rendezvous algorithm by which we stop the world for GC.
  *
  * This thread becomes the GC thread. Wait for all other threads to quiesce.
  * Then set rt->gcRunning and return.
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -593,33 +593,33 @@ struct ChunkInfo {
  *
  * In order to figure out how many Arenas will fit in a chunk, we need to know
  * how much extra space is available after we allocate the header data. This
  * is a problem because the header size depends on the number of arenas in the
  * chunk. The two dependent fields are bitmap and decommittedArenas.
  *
  * For the mark bitmap, we know that each arena will use a fixed number of full
  * bytes: ArenaBitmapBytes. The full size of the header data is this number
- * multiplied by the eventual number of arenas we have in the header. We, 
+ * multiplied by the eventual number of arenas we have in the header. We,
  * conceptually, distribute this header data among the individual arenas and do
- * not include it in the header. This way we do not have to worry about its 
+ * not include it in the header. This way we do not have to worry about its
  * variable size: it gets attached to the variable number we are computing.
  *
  * For the decommitted arena bitmap, we only have 1 bit per arena, so this
  * technique will not work. Instead, we observe that we do not have enough
- * header info to fill 8 full arenas: it is currently 4 on 64bit, less on 
+ * header info to fill 8 full arenas: it is currently 4 on 64bit, less on
  * 32bit. Thus, with current numbers, we need 64 bytes for decommittedArenas.
- * This will not become 63 bytes unless we double the data required in the 
- * header. Therefore, we just compute the number of bytes required to track 
+ * This will not become 63 bytes unless we double the data required in the
+ * header. Therefore, we just compute the number of bytes required to track
  * every possible arena and do not worry about slop bits, since there are too
  * few to usefully allocate.
  *
  * To actually compute the number of arenas we can allocate in a chunk, we
  * divide the amount of available space less the header info (not including
- * the mark bitmap which is distributed into the arena size) by the size of 
+ * the mark bitmap which is distributed into the arena size) by the size of
  * the arena (with the mark bitmap bytes it uses).
  */
 const size_t BytesPerArenaWithHeader = ArenaSize + ArenaBitmapBytes;
 const size_t ChunkDecommitBitmapBytes = ChunkSize / ArenaSize / JS_BITS_PER_BYTE;
 const size_t ChunkBytesAvailable = ChunkSize - sizeof(ChunkInfo) - ChunkDecommitBitmapBytes;
 const size_t ArenasPerChunk = ChunkBytesAvailable / BytesPerArenaWithHeader;
 
 /* A chunk bitmap contains enough mark bits for all the cells in a chunk. */
@@ -744,26 +744,44 @@ struct Chunk {
     ArenaHeader *allocateArena(JSCompartment *comp, AllocKind kind);
 
     void releaseArena(ArenaHeader *aheader);
 
     static Chunk *allocate(JSRuntime *rt);
 
     /* Must be called with the GC lock taken. */
     static inline void release(JSRuntime *rt, Chunk *chunk);
+    static inline void releaseList(JSRuntime *rt, Chunk *chunkListHead);
+
+    /* Must be called with the GC lock taken. */
+    inline void prepareToBeFreed(JSRuntime *rt);
+
+    /*
+     * Assuming that the info.prevp points to the next field of the previous
+     * chunk in a doubly-linked list, get that chunk.
+     */
+    Chunk *getPrevious() {
+        JS_ASSERT(info.prevp);
+        uintptr_t prevAddress = reinterpret_cast<uintptr_t>(info.prevp);
+        JS_ASSERT((prevAddress & ChunkMask) == offsetof(Chunk, info.next));
+        return reinterpret_cast<Chunk *>(prevAddress - offsetof(Chunk, info.next));
+    }
 
   private:
     inline void init();
 
     /* Search for a decommitted arena to allocate. */
     jsuint findDecommittedArenaOffset();
     ArenaHeader* fetchNextDecommittedArena();
 
+  public:
     /* Unlink and return the freeArenasHead. */
     inline ArenaHeader* fetchNextFreeArena(JSRuntime *rt);
+
+    inline void addArenaToFreeList(JSRuntime *rt, ArenaHeader *aheader);
 };
 
 JS_STATIC_ASSERT(sizeof(Chunk) == ChunkSize);
 
 class ChunkPool {
     Chunk   *emptyChunkListHead;
     size_t  emptyCount;
 
@@ -777,20 +795,23 @@ class ChunkPool {
     }
 
     inline bool wantBackgroundAllocation(JSRuntime *rt) const;
 
     /* Must be called with the GC lock taken. */
     inline Chunk *get(JSRuntime *rt);
 
     /* Must be called either during the GC or with the GC lock taken. */
-    inline void put(JSRuntime *rt, Chunk *chunk);
+    inline void put(Chunk *chunk);
 
-    /* Must be called either during the GC or with the GC lock taken. */
-    void expire(JSRuntime *rt, bool releaseAll);
+    /*
+     * Return the list of chunks that can be released outside the GC lock.
+     * Must be called either during the GC or with the GC lock taken.
+     */
+    Chunk *expire(JSRuntime *rt, bool releaseAll);
 
     /* Must be called either during the GC or with the GC lock taken. */
     JS_FRIEND_API(int64_t) countCleanDecommittedArenas(JSRuntime *rt);
 };
 
 inline uintptr_t
 Cell::address() const
 {
@@ -1715,17 +1736,17 @@ struct GCMarker : public JSTracer {
 
     bool isMarkStackEmpty() {
         return stack.isEmpty();
     }
 
     void drainMarkStack();
 
     inline void processMarkStackTop();
-    
+
     void pushObject(JSObject *obj) {
         pushTaggedPtr(ObjectTag, obj);
     }
 
     void pushType(types::TypeObject *type) {
         pushTaggedPtr(TypeTag, type);
     }
 
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2081,16 +2081,39 @@ types::UseNewType(JSContext *cx, JSScrip
         if (id == id_prototype(cx))
             return true;
     }
 
     return false;
 }
 
 bool
+types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script)
+{
+    if (!cx->typeInferenceEnabled() || !script->hasGlobal())
+        return true;
+
+    JSObject *proto;
+    if (!js_GetClassPrototype(cx, NULL, JSProto_Array, &proto, NULL))
+        return true;
+
+    while (proto) {
+        TypeObject *type = proto->getType(cx);
+        if (type->unknownProperties())
+            return true;
+        TypeSet *indexTypes = type->getProperty(cx, JSID_VOID, false);
+        if (!indexTypes || indexTypes->isOwnProperty(cx, type, true) || indexTypes->knownNonEmpty(cx))
+            return true;
+        proto = proto->getProto();
+    }
+
+    return false;
+}
+
+bool
 TypeCompartment::growPendingArray(JSContext *cx)
 {
     unsigned newCapacity = js::Max(unsigned(100), pendingCapacity * 2);
     PendingWork *newArray = (PendingWork *) OffTheBooks::calloc_(newCapacity * sizeof(PendingWork));
     if (!newArray) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -907,16 +907,23 @@ typedef HashSet<TypeObject *, TypeObject
 extern void
 MarkArgumentsCreated(JSContext *cx, JSScript *script);
 
 /* Whether to use a new type object when calling 'new' at script/pc. */
 bool
 UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
 
 /*
+ * Whether Array.prototype, or an object on its proto chain, has an
+ * indexed property.
+ */
+bool
+ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script);
+
+/*
  * Type information about a callsite. this is separated from the bytecode
  * information itself so we can handle higher order functions not called
  * directly via a bytecode.
  */
 struct TypeCallsite
 {
     JSScript *script;
     jsbytecode *pc;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3615,17 +3615,17 @@ js_PutBlockObject(JSContext *cx, JSBool 
     JS_ASSERT(count <= size_t(cx->regs().sp - fp->base() - depth));
 
     /* See comments in CheckDestructuring in frontend/Parser.cpp. */
     JS_ASSERT(count >= 1);
 
     if (normalUnwind) {
         uintN slot = JSSLOT_BLOCK_FIRST_FREE_SLOT;
         depth += fp->numFixed();
-        obj->copySlotRange(slot, fp->slots() + depth, count, true);
+        obj->copySlotRange(slot, fp->slots() + depth, count);
     }
 
     /* We must clear the private slot even with errors. */
     obj->setPrivate(NULL);
     fp->setScopeChainNoCallObj(*obj->internalScopeChain());
     return normalUnwind;
 }
 
@@ -4032,27 +4032,27 @@ JSObject::TradeGuts(JSContext *cx, JSObj
         memcpy(b, &tmp, sizeof tmp);
 
         if (a->isNative())
             a->shape_->setNumFixedSlots(reserved.newafixed);
         else
             a->shape_ = reserved.newashape;
 
         a->slots = reserved.newaslots;
-        a->copySlotRange(0, reserved.bvals.begin(), bcap, false);
+        a->initSlotRange(0, reserved.bvals.begin(), bcap);
         if (a->hasPrivate())
             a->setPrivate(bpriv);
 
         if (b->isNative())
             b->shape_->setNumFixedSlots(reserved.newbfixed);
         else
             b->shape_ = reserved.newbshape;
 
         b->slots = reserved.newbslots;
-        b->copySlotRange(0, reserved.avals.begin(), acap, false);
+        b->initSlotRange(0, reserved.avals.begin(), acap);
         if (b->hasPrivate())
             b->setPrivate(apriv);
 
         /* Make sure the destructor for reserved doesn't free the slots. */
         reserved.newaslots = NULL;
         reserved.newbslots = NULL;
     }
 }
@@ -4519,35 +4519,65 @@ js_InitClass(JSContext *cx, JSObject *ob
         return NULL;
     }
 
     return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs,
                                          ps, fs, static_ps, static_fs, ctorp, ctorKind);
 }
 
 void
-JSObject::copySlotRange(size_t start, const Value *vector, size_t length, bool valid)
-{
-    if (valid)
-        prepareSlotRangeForOverwrite(start, start + length);
-
+JSObject::getSlotRange(size_t start, size_t length,
+                       HeapValue **fixedStart, HeapValue **fixedEnd,
+                       HeapValue **slotsStart, HeapValue **slotsEnd)
+{
     JS_ASSERT(!isDenseArray());
     JS_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED));
+
     size_t fixed = numFixedSlots();
     if (start < fixed) {
         if (start + length < fixed) {
-            memcpy(fixedSlots() + start, vector, length * sizeof(Value));
+            *fixedStart = &fixedSlots()[start];
+            *fixedEnd = &fixedSlots()[start + length];
+            *slotsStart = *slotsEnd = NULL;
         } else {
             size_t localCopy = fixed - start;
-            memcpy(fixedSlots() + start, vector, localCopy * sizeof(Value));
-            memcpy(slots, vector + localCopy, (length - localCopy) * sizeof(Value));
+            *fixedStart = &fixedSlots()[start];
+            *fixedEnd = &fixedSlots()[start + localCopy];
+            *slotsStart = &slots[0];
+            *slotsEnd = &slots[length - localCopy];
         }
     } else {
-        memcpy(slots + start - fixed, vector, length * sizeof(Value));
-    }
+        *fixedStart = *fixedEnd = NULL;
+        *slotsStart = &slots[start - fixed];
+        *slotsEnd = &slots[start - fixed + length];
+    }
+}
+
+void
+JSObject::initSlotRange(size_t start, const Value *vector, size_t length)
+{
+    JSCompartment *comp = compartment();
+    HeapValue *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
+    getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
+    for (HeapValue *vp = fixedStart; vp != fixedEnd; vp++)
+        vp->init(comp, *vector++);
+    for (HeapValue *vp = slotsStart; vp != slotsEnd; vp++)
+        vp->init(comp, *vector++);
+}
+
+void
+JSObject::copySlotRange(size_t start, const Value *vector, size_t length)
+{
+    JSCompartment *comp = compartment();
+    HeapValue *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
+    getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
+    for (HeapValue *vp = fixedStart; vp != fixedEnd; vp++)
+        vp->set(comp, *vector++);
+    for (HeapValue *vp = slotsStart; vp != slotsEnd; vp++)
+        vp->set(comp, *vector++);
 }
 
 inline void
 JSObject::invalidateSlotRange(size_t start, size_t length)
 {
 #ifdef DEBUG
     JS_ASSERT(!isDenseArray());
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -634,16 +634,24 @@ struct JSObject : js::gc::Cell
     inline size_t dynamicSlotSize(JSMallocSizeOfFun mallocSizeOf) const;
 
     inline size_t numFixedSlots() const;
 
     static const uint32_t MAX_FIXED_SLOTS = 16;
 
   private:
     inline js::HeapValue* fixedSlots() const;
+
+    /*
+     * Get internal pointers to the range of values starting at start and
+     * running for length.
+     */
+    void getSlotRange(size_t start, size_t length,
+                      js::HeapValue **fixedStart, js::HeapValue **fixedEnd,
+                      js::HeapValue **slotsStart, js::HeapValue **slotsEnd);
   public:
 
     /* Accessors for properties. */
 
     /* Whether a slot is at a fixed offset from this object. */
     inline bool isFixedSlot(size_t slot);
 
     /* Index into the dynamic slots array to use for a dynamic slot. */
@@ -685,31 +693,34 @@ struct JSObject : js::gc::Cell
     inline bool hasContiguousSlots(size_t start, size_t count) const;
 
     inline void initializeSlotRange(size_t start, size_t count);
     inline void invalidateSlotRange(size_t start, size_t count);
 
     inline bool updateSlotsForSpan(JSContext *cx, size_t oldSpan, size_t newSpan);
 
   public:
-
     /*
      * Trigger the write barrier on a range of slots that will no longer be
      * reachable.
      */
     inline void prepareSlotRangeForOverwrite(size_t start, size_t end);
     inline void prepareElementRangeForOverwrite(size_t start, size_t end);
 
     /*
+     * Initialize a flat array of slots to this object at a start slot.  The
+     * caller must ensure that are enough slots.
+     */
+    void initSlotRange(size_t start, const js::Value *vector, size_t length);
+
+    /*
      * Copy a flat array of slots to this object at a start slot. Caller must
-     * ensure there are enough slots in this object. If |valid|, then the slots
-     * being overwritten hold valid data and must be invalidated for the write
-     * barrier.
+     * ensure there are enough slots in this object.
      */
-    void copySlotRange(size_t start, const js::Value *vector, size_t length, bool valid);
+    void copySlotRange(size_t start, const js::Value *vector, size_t length);
 
     inline uint32_t slotSpan() const;
 
     void rollbackProperties(JSContext *cx, uint32_t slotSpan);
 
 #ifdef DEBUG
     enum SentinelAllowed {
         SENTINEL_NOT_ALLOWED,
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -629,26 +629,28 @@ JSObject::initDenseArrayElementWithType(
     js::types::AddTypePropertyId(cx, this, JSID_VOID, val);
     initDenseArrayElement(idx, val);
 }
 
 inline void
 JSObject::copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count)
 {
     JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
+    JSCompartment *comp = compartment();
     for (unsigned i = 0; i < count; ++i)
-        elements[dstStart + i] = src[i];
+        elements[dstStart + i].set(comp, src[i]);
 }
 
 inline void
 JSObject::initDenseArrayElements(uintN dstStart, const js::Value *src, uintN count)
 {
     JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
+    JSCompartment *comp = compartment();
     for (unsigned i = 0; i < count; ++i)
-        elements[dstStart + i].init(src[i]);
+        elements[dstStart + i].init(comp, src[i]);
 }
 
 inline void
 JSObject::moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count)
 {
     JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
     JS_ASSERT(srcStart + count <= getDenseArrayCapacity());
 
--- a/js/src/jsonparser.h
+++ b/js/src/jsonparser.h
@@ -36,26 +36,30 @@
  * 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 ***** */
 
 #ifndef jsonparser_h___
 #define jsonparser_h___
 
+#include "mozilla/Attributes.h"
 #include "mozilla/RangedPtr.h"
 
 #include "jscntxt.h"
 #include "jsstr.h"
 
 /*
  * NB: This class must only be used on the stack as it contains a js::Value.
  */
 class JSONParser
 {
+    JSONParser(const JSONParser &other) MOZ_DELETE;
+    void operator=(const JSONParser &other) MOZ_DELETE;
+
   public:
     enum ErrorHandling { RaiseError, NoError };
     enum ParsingMode { StrictJSON, LegacyJSON };
 
   private:
     /* Data members */
 
     JSContext * const cx;
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -2427,25 +2427,32 @@ ASTSerializer::expression(ParseNode *pn,
             Value left, right;
             return expression(pn->pn_left, &left) &&
                    expression(pn->pn_right, &right) &&
                    builder.logicalExpression(pn->isKind(PNK_OR), left, right, &pn->pn_pos, dst);
         }
         return leftAssociate(pn, dst);
       }
 
-      case PNK_INC:
-      case PNK_DEC:
+      case PNK_PREINCREMENT:
+      case PNK_PREDECREMENT:
       {
-        bool incr = pn->isKind(PNK_INC);
-        bool prefix = pn->getOp() >= JSOP_INCNAME && pn->getOp() <= JSOP_DECELEM;
-
+        bool inc = pn->isKind(PNK_PREINCREMENT);
         Value expr;
         return expression(pn->pn_kid, &expr) &&
-               builder.updateExpression(expr, incr, prefix, &pn->pn_pos, dst);
+               builder.updateExpression(expr, inc, true, &pn->pn_pos, dst);
+      }
+
+      case PNK_POSTINCREMENT:
+      case PNK_POSTDECREMENT:
+      {
+        bool inc = pn->isKind(PNK_POSTINCREMENT);
+        Value expr;
+        return expression(pn->pn_kid, &expr) &&
+               builder.updateExpression(expr, inc, false, &pn->pn_pos, dst);
       }
 
       case PNK_ASSIGN:
       case PNK_ADDASSIGN:
       case PNK_SUBASSIGN:
       case PNK_BITORASSIGN:
       case PNK_BITXORASSIGN:
       case PNK_BITANDASSIGN:
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -43,16 +43,19 @@
  *
  * In order to avoid unnecessary js_LockGCThing/js_UnlockGCThing calls, these
  * native methods store strings (possibly newborn) converted from their 'this'
  * parameter and arguments on the stack: 'this' conversions at argv[-1], arg
  * conversions at their index (argv[0], argv[1]).  This is a legitimate method
  * of rooting things that might lose their newborn root due to subsequent GC
  * allocations in the same native method.
  */
+
+#include "mozilla/Attributes.h"
+
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
@@ -1353,18 +1356,18 @@ class RegExpPair
 /*
  * RegExpGuard factors logic out of String regexp operations.
  *
  * |optarg| indicates in which argument position RegExp flags will be found, if
  * present. This is a Mozilla extension and not part of any ECMA spec.
  */
 class RegExpGuard
 {
-    RegExpGuard(const RegExpGuard &);
-    void operator=(const RegExpGuard &);
+    RegExpGuard(const RegExpGuard &) MOZ_DELETE;
+    void operator=(const RegExpGuard &) MOZ_DELETE;
 
     JSContext   *cx;
     RegExpPair  rep;
     FlatMatch   fm;
 
     /*
      * Upper bound on the number of characters we are willing to potentially
      * waste on searching for RegExp meta-characters.
--- a/js/src/jsstrinlines.h
+++ b/js/src/jsstrinlines.h
@@ -35,16 +35,18 @@
  * 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 ***** */
 
 #ifndef jsstrinlines_h___
 #define jsstrinlines_h___
 
+#include "mozilla/Attributes.h"
+
 #include "jsatom.h"
 #include "jsstr.h"
 
 #include "jscntxtinlines.h"
 #include "jsgcinlines.h"
 #include "vm/String-inl.h"
 
 namespace js {
@@ -71,16 +73,19 @@ class StringBuffer
 
     CharBuffer cb;
 
     static inline bool checkLength(JSContext *cx, size_t length);
     inline bool checkLength(size_t length);
     JSContext *context() const { return cb.allocPolicy().context(); }
     jschar *extractWellSized();
 
+    StringBuffer(const StringBuffer &other) MOZ_DELETE;
+    void operator=(const StringBuffer &other) MOZ_DELETE;
+
   public:
     explicit inline StringBuffer(JSContext *cx);
     bool reserve(size_t len);
     bool resize(size_t len);
     bool append(const jschar c);
     bool append(const jschar *chars, size_t len);
     bool append(const jschar *begin, const jschar *end);
     bool append(JSString *str);
@@ -238,16 +243,19 @@ ValueToStringBuffer(JSContext *cx, const
 
     return ValueToStringBufferSlow(cx, v, sb);
 }
 
 class RopeBuilder {
     JSContext *cx;
     JSString *res;
 
+    RopeBuilder(const RopeBuilder &other) MOZ_DELETE;
+    void operator=(const RopeBuilder &other) MOZ_DELETE;
+
   public:
     RopeBuilder(JSContext *cx)
       : cx(cx), res(cx->runtime->emptyString)
     {}
 
     inline bool append(JSString *str) {
         res = js_ConcatStrings(cx, res, str);
         return !!res;
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -1682,19 +1682,17 @@ class TypedArrayTemplate
 
     static void copyIndexToValue(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp);
 
     static JSObject *
     createSubarray(JSContext *cx, JSObject *tarray, uint32_t begin, uint32_t end)
     {
         JS_ASSERT(tarray);
 
-        JS_ASSERT(0 <= begin);
         JS_ASSERT(begin <= getLength(tarray));
-        JS_ASSERT(0 <= end);
         JS_ASSERT(end <= getLength(tarray));
 
         JSObject *bufobj = getBuffer(tarray);
         JS_ASSERT(bufobj);
 
         JS_ASSERT(begin <= end);
         uint32_t length = end - begin;
 
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -39,16 +39,18 @@
 
 /*
  * PR assertion checker.
  */
 
 #ifndef jsutil_h___
 #define jsutil_h___
 
+#include "mozilla/Attributes.h"
+
 #include "js/Utility.h"
 
 /* Forward declarations. */
 struct JSContext;
 
 #ifdef __cplusplus
 namespace js {
 
@@ -218,18 +220,18 @@ class NeedsIncRef
 template <class RefCountable>
 class AutoRefCount
 {
     typedef RefCountable *****ConvertibleToBool;
 
     JSContext *const cx;
     RefCountable *obj;
 
-    AutoRefCount(const AutoRefCount &);
-    void operator=(const AutoRefCount &);
+    AutoRefCount(const AutoRefCount &other) MOZ_DELETE;
+    void operator=(const AutoRefCount &other) MOZ_DELETE;
 
   public:
     explicit AutoRefCount(JSContext *cx)
       : cx(cx), obj(NULL)
     {}
 
     AutoRefCount(JSContext *cx, NeedsIncRef<RefCountable> aobj)
       : cx(cx), obj(aobj.get())
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -7605,39 +7605,16 @@ mjit::Compiler::pushedSingleton(unsigned
 {
     if (!cx->typeInferenceEnabled())
         return NULL;
 
     types::TypeSet *types = analysis->pushedTypes(PC, pushed);
     return types->getSingleton(cx);
 }
 
-bool
-mjit::Compiler::arrayPrototypeHasIndexedProperty()
-{
-    if (!cx->typeInferenceEnabled() || !globalObj)
-        return true;
-
-    JSObject *proto;
-    if (!js_GetClassPrototype(cx, NULL, JSProto_Array, &proto, NULL))
-        return true;
-
-    while (proto) {
-        types::TypeObject *type = proto->getType(cx);
-        if (type->unknownProperties())
-            return true;
-        types::TypeSet *indexTypes = type->getProperty(cx, JSID_VOID, false);
-        if (!indexTypes || indexTypes->isOwnProperty(cx, type, true) || indexTypes->knownNonEmpty(cx))
-            return true;
-        proto = proto->getProto();
-    }
-
-    return false;
-}
-
 /*
  * Barriers overview.
  *
  * After a property fetch finishes, we may need to do type checks on it to make
  * sure it matches the pushed type set for this bytecode. This can be either
  * because there is a type barrier at the bytecode, or because we cannot rule
  * out an undefined result. For such accesses, we push a register pair, and
  * then use those registers to check the fetched type matches the inferred
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -481,18 +481,16 @@ private:
 
     InvariantCodePatch *getInvariantPatch(unsigned index) {
         return &callSites[index].loopPatch;
     }
     jsbytecode *getInvariantPC(unsigned index) {
         return callSites[index].inlinepc;
     }
 
-    bool arrayPrototypeHasIndexedProperty();
-
     bool activeFrameHasMultipleExits() {
         ActiveFrame *na = a;
         while (na->parent) {
             if (na->exitState)
                 return true;
             na = na->parent;
         }
         return false;
--- a/js/src/methodjit/FastBuiltins.cpp
+++ b/js/src/methodjit/FastBuiltins.cpp
@@ -876,17 +876,17 @@ mjit::Compiler::inlineNativeFunction(uin
              * in an iterator --- when popping elements we don't account for
              * suppressing deleted properties in active iterators.
              *
              * Constraints propagating properties directly into the result
              * type set are generated by TypeConstraintCall during inference.
              */
             if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY |
                                            types::OBJECT_FLAG_ITERATED) &&
-                !arrayPrototypeHasIndexedProperty()) {
+                !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
                 bool packed = !thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
                 return compileArrayPopShift(thisValue, packed, native == js::array_pop);
             }
         }
     } else if (argc == 1) {
         FrameEntry *arg = frame.peek(-1);
         types::TypeSet *argTypes = frame.extra(arg).types;
         if (!argTypes)
@@ -926,17 +926,17 @@ mjit::Compiler::inlineNativeFunction(uin
         }
         if (native == js::array_push &&
             thisType == JSVAL_TYPE_OBJECT && type == JSVAL_TYPE_INT32) {
             /*
              * Constraints propagating properties into the 'this' object are
              * generated by TypeConstraintCall during inference.
              */
             if (!thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
-                !arrayPrototypeHasIndexedProperty()) {
+                !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
                 return compileArrayPush(thisValue, arg);
             }
         }
         if (native == js::array_concat && argType == JSVAL_TYPE_OBJECT &&
             thisType == JSVAL_TYPE_OBJECT && type == JSVAL_TYPE_OBJECT &&
             !thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
             !argTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY)) {
             return compileArrayConcat(thisTypes, argTypes, thisValue, arg);
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1516,17 +1516,17 @@ mjit::Compiler::jsop_setelem(bool popGua
     frame.forgetMismatchedObject(obj);
 
     // If the object is definitely a dense array or a typed array we can generate
     // code directly without using an inline cache.
     if (cx->typeInferenceEnabled()) {
         types::TypeSet *types = analysis->poppedTypes(PC, 2);
 
         if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
-            !arrayPrototypeHasIndexedProperty()) {
+            !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
             // Inline dense array path.
             jsop_setelem_dense();
             return true;
         }
 
 #ifdef JS_METHODJIT_TYPED_ARRAY
         if ((value->mightBeType(JSVAL_TYPE_INT32) || value->mightBeType(JSVAL_TYPE_DOUBLE)) &&
             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) {
@@ -2108,17 +2108,17 @@ mjit::Compiler::jsop_getelem(bool isCall
         if (types->isLazyArguments(cx) && !outerScript->analysis()->modifiesArguments()) {
             // Inline arguments path.
             jsop_getelem_args();
             return true;
         }
 
         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
-            !arrayPrototypeHasIndexedProperty()) {
+            !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
             // Inline dense array path.
             bool packed = !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
             jsop_getelem_dense(packed);
             return true;
         }
 
 #ifdef JS_METHODJIT_TYPED_ARRAY
         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -1120,18 +1120,20 @@ FrameState::frameSlot(ActiveFrame *a, co
         return analyze::ThisSlot();
     if (fe == a->callee_)
         return analyze::CalleeSlot();
     JS_NOT_REACHED("Bad fe");
     return 0;
 }
 
 inline JSC::MacroAssembler::Address
-FrameState::addressForInlineReturn() const
+FrameState::addressForInlineReturn()
 {
+    if (a->callee_->isTracked())
+        discardFe(a->callee_);
     return addressOf(a->callee_);
 }
 
 inline JSC::MacroAssembler::Address
 FrameState::addressForDataRemat(const FrameEntry *fe) const
 {
     if (fe->isCopy() && !fe->data.synced())
         fe = fe->copyOf();
--- a/js/src/methodjit/FrameState.h
+++ b/js/src/methodjit/FrameState.h
@@ -872,17 +872,17 @@ class FrameState
 
     // Returns an address, relative to the StackFrame, that represents where
     // this FrameEntry is backed in memory. This is not necessarily its
     // canonical address, but the address for which the payload has been synced
     // to memory. The caller guarantees that the payload has been synced.
     Address addressForDataRemat(const FrameEntry *fe) const;
 
     // Inside an inline frame, the address for the return value in the caller.
-    Address addressForInlineReturn() const;
+    Address addressForInlineReturn();
 
     inline StateRemat dataRematInfo(const FrameEntry *fe) const;
 
     /*
      * This is similar to freeReg(ownRegForData(fe)) - except no movement takes place.
      * The fe is simply invalidated as if it were popped. This can be used to free
      * registers in the working area of the stack. Obviously, this can only be called
      * in infallible code that will pop these entries soon after.
--- a/js/src/methodjit/LoopState.cpp
+++ b/js/src/methodjit/LoopState.cpp
@@ -1710,17 +1710,17 @@ LoopState::definiteArrayAccess(const SSA
     if (objTypes->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT ||
         elemTypes->getKnownTypeTag(cx) != JSVAL_TYPE_INT32) {
         return false;
     }
 
     if (objTypes->hasObjectFlags(cx, OBJECT_FLAG_NON_DENSE_ARRAY))
         return false;
 
-    if (cc.arrayPrototypeHasIndexedProperty())
+    if (ArrayPrototypeHasIndexedProperty(cx, outerScript))
         return false;
 
     uint32_t objSlot;
     int32_t objConstant;
     CrossSSAValue objv(CrossScriptSSA::OUTER_FRAME, obj);
     if (!getEntryValue(objv, &objSlot, &objConstant) || objSlot == UNASSIGNED || objConstant != 0)
         return false;
     if (!loopInvariantEntry(objSlot))
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2328,55 +2328,34 @@ DumpScope(JSContext *cx, JSObject *obj, 
         fprintf(fp, "%3u %p ", i++, (void *) sprop);
         ((Shape *) sprop)->dump(cx, fp);
     }
 }
 
 static JSBool
 DumpStats(JSContext *cx, uintN argc, jsval *vp)
 {
-    uintN i;
-    JSString *str;
-    jsid id;
-    JSObject *obj2;
-    JSProperty *prop;
-    Value value;
-
     jsval *argv = JS_ARGV(cx, vp);
-    for (i = 0; i < argc; i++) {
-        str = JS_ValueToString(cx, argv[i]);
+    for (uintN i = 0; i < argc; i++) {
+        JSString *str = JS_ValueToString(cx, argv[i]);
         if (!str)
             return JS_FALSE;
         argv[i] = STRING_TO_JSVAL(str);
         JSFlatString *flatStr = JS_FlattenString(cx, str);
         if (!flatStr)
             return JS_FALSE;
         if (JS_FlatStringEqualsAscii(flatStr, "atom")) {
             js_DumpAtoms(cx, gOutFile);
         } else if (JS_FlatStringEqualsAscii(flatStr, "global")) {
             DumpScope(cx, cx->globalObject, stdout);
         } else {
-            if (!JS_ValueToId(cx, STRING_TO_JSVAL(str), &id))
-                return JS_FALSE;
-            JSObject *obj;
-            if (!js_FindProperty(cx, id, false, &obj, &obj2, &prop))
-                return JS_FALSE;
-            if (prop) {
-                if (!obj->getGeneric(cx, id, &value))
-                    return JS_FALSE;
-            }
-            if (!prop || !value.isObjectOrNull()) {
-                fputs("js: invalid stats argument ", gErrFile);
-                JS_FileEscapedString(gErrFile, str, 0);
-                putc('\n', gErrFile);
-                continue;
-            }
-            obj = value.toObjectOrNull();
-            if (obj)
-                DumpScope(cx, obj, stdout);
+            fputs("js: invalid stats argument ", gErrFile);
+            JS_FileEscapedString(gErrFile, str, 0);
+            putc('\n', gErrFile);
+            continue;
         }
     }
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
 DumpHeap(JSContext *cx, uintN argc, jsval *vp)
@@ -4112,17 +4091,17 @@ static const char *const shell_help_mess
 "  dis and disfile take these options as preceeding string arguments\n"
 "    \"-r\" (disassemble recursively)\n"
 "    \"-l\" (show line numbers)",
 "dissrc([fun])            Disassemble functions with source lines",
 "dumpHeap([fileName[, start[, toFind[, maxDepth[, toIgnore]]]]])\n"
 "  Interface to JS_DumpHeap with output sent to file",
 "dumpObject()             Dump an internal representation of an object",
 "notes([fun])             Show source notes for functions",
-"stats([string ...])      Dump 'arena', 'atom', 'global' stats",
+"stats([string ...])      Dump 'atom' or 'global' stats",
 "findReferences(target)\n"
 "  Walk the entire heap, looking for references to |target|, and return a\n"
 "  \"references object\" describing what we found.\n"
 "\n"
 "  Each property of the references object describes one kind of reference. The\n"
 "  property's name is the label supplied to MarkObject, JS_CALL_TRACER, or what\n"
 "  have you, prefixed with \"edge: \" to avoid collisions with system properties\n"
 "  (like \"toString\" and \"__proto__\"). The property's value is an array of things\n"
--- a/js/src/shell/jsworkers.cpp
+++ b/js/src/shell/jsworkers.cpp
@@ -94,26 +94,24 @@ extern size_t gMaxStackSize;
  * the parent-child relationship is a partial order.)
  */
 
 namespace js {
 namespace workers {
 
 template <class T, class AllocPolicy>
 class Queue {
-  private:
     typedef Vector<T, 4, AllocPolicy> Vec;
     Vec v1;
     Vec v2;
     Vec *front;
     Vec *back;
 
-    // Queue is not copyable.
-    Queue(const Queue &);
-    Queue & operator=(const Queue &);
+    Queue(const Queue &) MOZ_DELETE;
+    Queue & operator=(const Queue &) MOZ_DELETE;
 
   public:
     Queue() : front(&v1), back(&v2) {}
     bool push(T t) { return back->append(t); }
     bool empty() { return front->empty() && back->empty(); }
 
     T pop() {
         if (front->empty()) {
--- a/js/src/tests/js1_5/extensions/jstests.list
+++ b/js/src/tests/js1_5/extensions/jstests.list
@@ -40,27 +40,27 @@ script regress-319683.js
 script regress-322957.js
 script regress-327608.js
 script regress-328443.js
 script regress-328556.js
 skip script regress-330569.js # Yarr doesn't bail on complex regexps.
 script regress-333541.js
 skip script regress-335700.js # bug xxx - reftest hang, BigO
 skip-if(!xulRuntime.shell||Android) slow script regress-336409-1.js # no results reported.
-skip-if(!xulRuntime.shell&&((Android||(isDebugBuild&&xulRuntime.OS=="Linux")||xulRuntime.XPCOMABI.match(/x86_64/)))) silentfail script regress-336409-2.js # can fail silently due to out of memory, bug 615011 - timeouts on slow debug Linux
-skip-if(!xulRuntime.shell||Android) silentfail script regress-336410-1.js # can fail silently due to out of memory
-skip-if(!xulRuntime.shell&&((isDebugBuild&&xulRuntime.OS=="Linux")||Android||xulRuntime.XPCOMABI.match(/x86_64/)||xulRuntime.OS=="WINNT")) silentfail script regress-336410-2.js # can fail silently due to out of memory, bug 621348 - timeouts on slow debug Linux
+skip-if(!xulRuntime.shell&&((Android||(isDebugBuild&&xulRuntime.OS=="Linux")||xulRuntime.XPCOMABI.match(/x86_64/)))) silentfail slow script regress-336409-2.js # can fail silently due to out of memory, bug 615011 - timeouts on slow debug Linux
+skip-if(!xulRuntime.shell||Android) silentfail slow script regress-336410-1.js # can fail silently due to out of memory
+skip-if(!xulRuntime.shell&&((isDebugBuild&&xulRuntime.OS=="Linux")||Android||xulRuntime.XPCOMABI.match(/x86_64/)||xulRuntime.OS=="WINNT")) silentfail slow script regress-336410-2.js # can fail silently due to out of memory, bug 621348 - timeouts on slow debug Linux
 script regress-338804-01.js
 script regress-338804-02.js
 script regress-338804-03.js
 script regress-339685.js
 script regress-341956-01.js
 script regress-341956-02.js
 script regress-341956-03.js
-skip-if(!xulRuntime.shell&&(Android||xulRuntime.OS=="WINNT"||xulRuntime.OS=="Linux")) silentfail script regress-342960.js # bug 528464
+skip-if(!xulRuntime.shell&&(Android||xulRuntime.OS=="WINNT"||xulRuntime.OS=="Linux")) silentfail slow script regress-342960.js # bug 528464
 skip script regress-345967.js # slow
 script regress-346494-01.js
 script regress-346494.js
 random script regress-347306-02.js # BigO
 script regress-348986.js
 script regress-350312-01.js
 script regress-350312-02.js
 script regress-350312-03.js
--- a/js/src/vm/BooleanObject.h
+++ b/js/src/vm/BooleanObject.h
@@ -36,16 +36,18 @@
  * 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 ***** */
 
 #ifndef BooleanObject_h___
 #define BooleanObject_h___
 
+#include "mozilla/Attributes.h"
+
 #include "jsbool.h"
 
 namespace js {
 
 class BooleanObject : public ::JSObject
 {
     /* Stores this Boolean object's [[PrimitiveValue]]. */
     static const uintN PRIMITIVE_VALUE_SLOT = 0;
@@ -75,15 +77,15 @@ class BooleanObject : public ::JSObject
         setSlot(PRIMITIVE_VALUE_SLOT, BooleanValue(b));
     }
 
     /* For access to init, as Boolean.prototype is special. */
     friend JSObject *
     ::js_InitBooleanClass(JSContext *cx, JSObject *global);
 
   private:
-    BooleanObject();
-    BooleanObject &operator=(const BooleanObject &bo);
+    BooleanObject() MOZ_DELETE;
+    BooleanObject &operator=(const BooleanObject &bo) MOZ_DELETE;
 };
 
 } // namespace js
 
 #endif /* BooleanObject_h__ */
--- a/js/src/vm/CallObject-inl.h
+++ b/js/src/vm/CallObject-inl.h
@@ -160,18 +160,18 @@ CallObject::initVarUnchecked(uintN i, co
     JS_ASSERT(i < fun->script()->bindings.countVars());
     initSlotUnchecked(RESERVED_SLOTS + fun->nargs + i, v);
 }
 
 inline void
 CallObject::copyValues(uintN nargs, Value *argv, uintN nvars, Value *slots)
 {
     JS_ASSERT(slotInRange(RESERVED_SLOTS + nargs + nvars, SENTINEL_ALLOWED));
-    copySlotRange(RESERVED_SLOTS, argv, nargs, true);
-    copySlotRange(RESERVED_SLOTS + nargs, slots, nvars, true);
+    copySlotRange(RESERVED_SLOTS, argv, nargs);
+    copySlotRange(RESERVED_SLOTS + nargs, slots, nvars);
 }
 
 inline js::HeapValueArray
 CallObject::argArray()
 {
     js::DebugOnly<JSFunction*> fun = getCalleeFunction();
     JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS, fun->nargs));
     return HeapValueArray(getSlotAddress(RESERVED_SLOTS));
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -36,16 +36,18 @@
  * 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 ***** */
 
 #ifndef GlobalObject_h___
 #define GlobalObject_h___
 
+#include "mozilla/Attributes.h"
+
 #include "jsarray.h"
 #include "jsbool.h"
 #include "jsfun.h"
 #include "jsiter.h"
 #include "jsnum.h"
 #include "jstypedarray.h"
 
 #include "js/Vector.h"
@@ -85,16 +87,19 @@ class Debugger;
  * The first two ranges are necessary to implement js::FindClassObject,
  * js::FindClassPrototype, and spec language speaking in terms of "the original
  * Array prototype object", or "as if by the expression new Array()" referring
  * to the original Array constructor.  The third range stores the (writable and
  * even deletable) Object, Array, &c. properties (although a slot won't be used
  * again if its property is deleted and readded).
  */
 class GlobalObject : public ::JSObject {
+    GlobalObject(const GlobalObject &other) MOZ_DELETE;
+    void operator=(const GlobalObject &other) MOZ_DELETE;
+
     /*
      * Count of slots to store built-in constructors, prototypes, and initial
      * visible properties for the constructors.
      */
     static const uintN STANDARD_CLASS_SLOTS  = JSProto_LIMIT * 3;
 
     /* One-off properties stored after slots for built-ins. */
     static const uintN THROWTYPEERROR          = STANDARD_CLASS_SLOTS;
--- a/js/src/vm/NumberObject.h
+++ b/js/src/vm/NumberObject.h
@@ -36,16 +36,18 @@
  * 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 ***** */
 
 #ifndef NumberObject_h___
 #define NumberObject_h___
 
+#include "mozilla/Attributes.h"
+
 #include "jsnum.h"
 
 namespace js {
 
 class NumberObject : public ::JSObject
 {
     /* Stores this Number object's [[PrimitiveValue]]. */
     static const uintN PRIMITIVE_VALUE_SLOT = 0;
@@ -75,15 +77,15 @@ class NumberObject : public ::JSObject
         setSlot(PRIMITIVE_VALUE_SLOT, NumberValue(d));
     }
 
     /* For access to init, as Number.prototype is special. */
     friend JSObject *
     ::js_InitNumberClass(JSContext *cx, JSObject *global);
 
   private:
-    NumberObject();
-    NumberObject &operator=(const NumberObject &so);
+    NumberObject() MOZ_DELETE;
+    NumberObject &operator=(const NumberObject &so) MOZ_DELETE;
 };
 
 } // namespace js
 
 #endif /* NumberObject_h__ */
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -36,16 +36,18 @@
  * 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 ***** */
 
 #ifndef RegExpObject_h__
 #define RegExpObject_h__
 
+#include "mozilla/Attributes.h"
+
 #include <stddef.h>
 #include "jsobj.h"
 
 #include "js/TemplateLib.h"
 
 #include "yarr/Yarr.h"
 #if ENABLE_YARR_JIT
 #include "yarr/YarrJIT.h"
@@ -195,18 +197,18 @@ class RegExpObject : public ::JSObject
 
     /*
      * Compute the initial shape to associate with fresh RegExp objects,
      * encoding their initial properties. Return the shape after
      * changing this regular expression object's last property to it.
      */
     Shape *assignInitialShape(JSContext *cx);
 
-    RegExpObject();
-    RegExpObject &operator=(const RegExpObject &reo);
+    RegExpObject() MOZ_DELETE;
+    RegExpObject &operator=(const RegExpObject &reo) MOZ_DELETE;
 }; /* class RegExpObject */
 
 /* Either builds a new RegExpObject or re-initializes an existing one. */
 class RegExpObjectBuilder
 {
     typedef detail::RegExpPrivate RegExpPrivate;
 
     JSContext       *cx;
--- a/js/src/vm/StringObject.h
+++ b/js/src/vm/StringObject.h
@@ -36,16 +36,18 @@
  * 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 ***** */
 
 #ifndef StringObject_h___
 #define StringObject_h___
 
+#include "mozilla/Attributes.h"
+
 #include "jsobj.h"
 #include "jsstr.h"
 
 namespace js {
 
 class StringObject : public ::JSObject
 {
     static const uintN PRIMITIVE_THIS_SLOT = 0;
@@ -90,15 +92,15 @@ class StringObject : public ::JSObject
     /*
      * Compute the initial shape to associate with fresh String objects, which
      * encodes the initial length property. Return the shape after changing
      * this String object's last property to it.
      */
     Shape *assignInitialShape(JSContext *cx);
 
   private:
-    StringObject();
-    StringObject &operator=(const StringObject &so);
+    StringObject() MOZ_DELETE;
+    StringObject &operator=(const StringObject &so) MOZ_DELETE;
 };
 
 } // namespace js
 
 #endif /* StringObject_h__ */
--- a/js/xpconnect/idl/nsIXPCScriptable.idl
+++ b/js/xpconnect/idl/nsIXPCScriptable.idl
@@ -68,17 +68,17 @@
 
 /**
  * Note: This is not really an XPCOM interface.  For example, callers must
  * guarantee that they set the *_retval of the various methods that return a
  * boolean to PR_TRUE before making the call.  Implementations may skip writing
  * to *_retval unless they want to return PR_FALSE.
  */
 
-[uuid(9cadb17b-9990-461a-8e01-cf50aeffc2c5)]
+[uuid(a40ce52e-2d8c-400f-9af2-f8784a656070)]
 interface nsIXPCScriptable : nsISupports
 {
     /* bitflags used for 'flags' (only 32 bits available!) */
 
     const PRUint32 WANT_PRECREATE                   = 1 <<  0;
     const PRUint32 WANT_CREATE                      = 1 <<  1;
     const PRUint32 WANT_POSTCREATE                  = 1 <<  2;
     const PRUint32 WANT_ADDPROPERTY                 = 1 <<  3;
@@ -186,24 +186,16 @@ interface nsIXPCScriptable : nsISupports
 
     boolean equality(in nsIXPConnectWrappedNative wrapper,
                     in JSContextPtr cx, in JSObjectPtr obj, in jsval val);
 
     JSObjectPtr outerObject(in nsIXPConnectWrappedNative wrapper,
                             in JSContextPtr cx, in JSObjectPtr obj);
 
     void postCreatePrototype(in JSContextPtr cx, in JSObjectPtr proto);
-
-    /**
-     * Notify that we're about to create the prototype object for this class,
-     * and ask what prototype we should use for that.
-     */
-    void preCreatePrototype(in JSContextPtr cx,
-                            in JSObjectPtr globalObj,
-                            out JSObjectPtr protoProtoObj);
 };
 
 %{ C++
 
 #include "nsAutoPtr.h"
 
 #define NS_XPCCLASSINFO_IID \
 { 0x9a5b0342, 0x0f70, 0x4d31, \
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -960,20 +960,30 @@ mozJSComponentLoader::GlobalForLocation(
             LOG(("Failed to write to cache\n"));
         }
     }
 
     // Assign aGlobal here so that it's available to recursive imports.
     // See bug 384168.
     *aGlobal = global;
 
-    if (!JS_ExecuteScriptVersion(cx, global, script, NULL, JSVERSION_LATEST)) {
+    uint32 oldopts = JS_GetOptions(cx);
+    JS_SetOptions(cx, oldopts |
+                  (exception ? JSOPTION_DONT_REPORT_UNCAUGHT : 0));
+    bool ok = JS_ExecuteScriptVersion(cx, global, script, NULL, JSVERSION_LATEST);
+    JS_SetOptions(cx, oldopts);
+
+    if (!ok) {
 #ifdef DEBUG_shaver_off
         fprintf(stderr, "mJCL: failed to execute %s\n", nativePath.get());
 #endif
+        if (exception) {
+            JS_GetPendingException(cx, exception);
+            JS_ClearPendingException(cx);
+        }
         *aGlobal = nsnull;
         return NS_ERROR_FAILURE;
     }
 
     /* Freed when we remove from the table. */
     *aLocation = ToNewCString(nativePath);
     if (!*aLocation) {
         *aGlobal = nsnull;
--- a/js/xpconnect/public/xpc_map_end.h
+++ b/js/xpconnect/public/xpc_map_end.h
@@ -223,21 +223,16 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::OuterOb
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #ifndef XPC_MAP_WANT_POST_CREATE_PROTOTYPE
 NS_IMETHODIMP XPC_MAP_CLASSNAME::PostCreatePrototype(JSContext *cx, JSObject *proto)
     {return NS_OK;}
 #endif
 
-#ifndef XPC_MAP_WANT_PRE_CREATE_PROTOTYPE
-NS_IMETHODIMP XPC_MAP_CLASSNAME::PreCreatePrototype(JSContext *cx, JSObject *global, JSObject **protoProto)
-    {*protoProto = nsnull; return NS_OK;}
-#endif
-
 /**************************************************************/
 
 #undef XPC_MAP_CLASSNAME
 #undef XPC_MAP_QUOTED_CLASSNAME
 
 #ifdef XPC_MAP_WANT_PRECREATE
 #undef XPC_MAP_WANT_PRECREATE
 #endif
@@ -313,15 +308,11 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::PreCrea
 #ifdef XPC_MAP_WANT_OUTER_OBJECT
 #undef XPC_MAP_WANT_OUTER_OBJECT
 #endif
 
 #ifdef XPC_MAP_WANT_POST_CREATE_PROTOTYPE
 #undef XPC_MAP_WANT_POST_CREATE_PROTOTYPE
 #endif
 
-#ifdef XPC_MAP_WANT_PRE_CREATE_PROTOTYPE
-#undef XPC_MAP_WANT_PRE_CREATE_PROTOTYPE
-#endif
-
 #ifdef XPC_MAP_FLAGS
 #undef XPC_MAP_FLAGS
 #endif
--- a/js/xpconnect/src/XPCWrappedNativeProto.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp
@@ -118,32 +118,20 @@ XPCWrappedNativeProto::Init(XPCCallConte
                 &XPC_WN_NoMods_NoCall_Proto_JSClass;
         }
     } else {
         jsclazz = &XPC_WN_NoMods_NoCall_Proto_JSClass;
     }
 
     JSObject *parent = mScope->GetGlobalJSObject();
 
-    JSObject *protoProto = nsnull;
-    if (callback) {
-        nsresult rv = callback->PreCreatePrototype(ccx, parent, &protoProto);
-        if (NS_FAILED(rv)) {
-            mJSProtoObject = nsnull;
-            XPCThrower::Throw(rv, ccx);
-            return false;
-        }
-    }
-    if (!protoProto) {
-        protoProto = mScope->GetPrototypeJSObject();
-    }
-
     mJSProtoObject =
         xpc_NewSystemInheritingJSObject(ccx, js::Jsvalify(jsclazz),
-                                        protoProto, true, parent);
+                                        mScope->GetPrototypeJSObject(),
+                                        true, parent);
 
     JSBool ok = mJSProtoObject && JS_SetPrivate(ccx, mJSProtoObject, this);
 
     if (ok && callback) {
         nsresult rv = callback->PostCreatePrototype(ccx, mJSProtoObject);
         if (NS_FAILED(rv)) {
             JS_SetPrivate(ccx, mJSProtoObject, nsnull);
             mJSProtoObject = nsnull;
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/importer.jsm
@@ -0,0 +1,1 @@
+Components.utils.import("resource://test/syntax_error.jsm");
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_import_fail.js
@@ -0,0 +1,10 @@
+function run_test()
+{
+  try {
+    Components.utils.import("resource://test/importer.jsm");
+    do_check_true(false, "import should not succeed.");
+  } catch (x) {
+    do_check_neq(x.fileName.indexOf("syntax_error.jsm"), -1);
+    do_check_eq(x.lineNumber, 1);
+  }
+}
\ No newline at end of file
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -9,16 +9,17 @@ tail =
 [test_bug604362.js]
 [test_bug608142.js]
 [test_bug641378.js]
 [test_bug677864.js]
 [test_bug711404.js]
 [test_bug_442086.js]
 [test_file.js]
 [test_import.js]
+[test_import_fail.js]
 [test_js_weak_references.js]
 [test_reflect_parse.js]
 [test_localeCompare.js]
 # Bug 676965: test fails consistently on Android
 fail-if = os == "android"
 [test_recursive_import.js]
 [test_xpcomutils.js]
 [test_unload.js]
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4585,26 +4585,32 @@ nsLayoutUtils::IsContainerForFontSizeInf
    * (possibly with inline elements) flowing within a block to count the
    * block (or higher) as its container.
    *
    * We also want form controls, including the text in the anonymous
    * content inside of them, to match each other and the text next to
    * them, so they and their anonymous content should also not be a
    * container.
    *
+   * However, because we can't reliably compute sizes across XUL during
+   * reflow, any XUL frame with a XUL parent is always a container.
+   *
    * There are contexts where it would be nice if some blocks didn't
    * count as a container, so that, for example, an indented quotation
    * didn't end up with a smaller font size.  However, it's hard to
    * distinguish these situations where we really do want the indented
    * thing to count as a container, so we don't try, and blocks are
    * always containers.
    */
-  bool isInline = aFrame->GetStyleDisplay()->mDisplay ==
-                    NS_STYLE_DISPLAY_INLINE ||
-                  aFrame->GetContent()->IsInNativeAnonymousSubtree();
+  bool isInline = (aFrame->GetStyleDisplay()->mDisplay ==
+                     NS_STYLE_DISPLAY_INLINE ||
+                   (aFrame->GetContent() &&
+                    aFrame->GetContent()->IsInNativeAnonymousSubtree())) &&
+                  !(aFrame->IsBoxFrame() && aFrame->GetParent() &&
+                    aFrame->GetParent()->IsBoxFrame());
   NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) || isInline,
                "line participants must not be containers");
   NS_ASSERTION(aFrame->GetType() != nsGkAtoms::bulletFrame || isInline,
                "bullets should not be containers");
   return !isInline;
 }
 
 static bool
@@ -4623,20 +4629,36 @@ ShouldInflateFontsForContainer(const nsI
 }
 
 nscoord
 nsLayoutUtils::InflationMinFontSizeFor(const nsHTMLReflowState &aReflowState)
 {
 #ifdef DEBUG
   {
     const nsHTMLReflowState *rs = &aReflowState;
-    const nsIFrame *f = aReflowState.frame;
+    nsIFrame *f = aReflowState.frame;
     for (; rs; rs = rs->parentReflowState, f = f->GetParent()) {
       NS_ABORT_IF_FALSE(rs->frame == f,
                         "reflow state parentage must match frame parentage");
+      nsIScrollableFrame *sf;
+      NS_ABORT_IF_FALSE(rs->parentReflowState ||
+                        IsContainerForFontSizeInflation(f) ||
+                        // OK if NS_FRAME_IN_REFLOW is not set on
+                        // (non-null) parent, since its ancestors have a
+                        // real size.  (Do we set NS_FRAME_IN_REFLOW
+                        // correctly for xul?)
+                        !(f->GetParent()->GetStateBits() &
+                          NS_FRAME_IN_REFLOW) ||
+                        // ugly exception, but ok because the
+                        // child is a container
+                        (f->GetType() == nsGkAtoms::scrollFrame &&
+                         (sf = do_QueryFrame(f)) &&
+                         (IsContainerForFontSizeInflation(
+                            sf->GetScrolledFrame()))),
+                        "must hit container at top of reflow state chain");
     }
   }
 #endif
 
   if (!FontSizeInflationEnabled(aReflowState.frame->PresContext())) {
     return 0;
   }
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5813,17 +5813,38 @@ PresShell::HandleEvent(nsIFrame        *
     }
 
     if (retargetEventDoc) {
       nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell();
       if (!presShell)
         return NS_OK;
 
       if (presShell != this) {
-        return presShell->HandleEvent(presShell->GetRootFrame(), aEvent, true, aEventStatus);
+        nsIFrame* frame = presShell->GetRootFrame();
+        if (!frame) {
+          if (aEvent->message == NS_QUERY_TEXT_CONTENT ||
+              NS_IS_CONTENT_COMMAND_EVENT(aEvent)) {
+            return NS_OK;
+          }
+
+          nsIView* view = presShell->GetViewManager()->GetRootView();
+          while (view && !view->GetFrame()) {
+            view = view->GetParent();
+          }
+
+          if (view) {
+            frame = view->GetFrame();
+          }
+        }
+
+        if (!frame)
+          return NS_OK;
+
+        nsCOMPtr<nsIPresShell> shell = frame->PresContext()->GetPresShell();
+        return shell->HandleEvent(frame, aEvent, true, aEventStatus);
       }
     }
   }
 
   // Check for a theme change up front, since the frame type is irrelevant
   if (aEvent->message == NS_THEMECHANGED && mPresContext) {
     mPresContext->ThemeChanged();
     return NS_OK;
--- a/layout/base/tests/Makefile.in
+++ b/layout/base/tests/Makefile.in
@@ -376,16 +376,17 @@ ifeq (,$(filter windows,$(MOZ_WIDGET_TOO
 endif
 
 _BROWSER_FILES = \
 	browser_bug617076.js \
 	$(NULL)
 
 _INFLATION_REFTEST_FILES = \
 		$(shell find $(srcdir)/font-inflation/ -name '*.html' -o -name '*.xhtml') \
+		$(srcdir)/../../reftests/webm-video/black140x100.webm \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 libs:: $(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
 libs:: $(_INFLATION_REFTEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)/font-inflation/
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/font-inflation/video-1.html
@@ -0,0 +1,2 @@
+<!DOCTYPE HTML>
+<video src="black140x100.webm"></video>
--- a/layout/base/tests/test_font_inflation_reftests.html
+++ b/layout/base/tests/test_font_inflation_reftests.html
@@ -41,16 +41,17 @@ var gTests = [
   "== input-text-2.html input-text-2-ref.html",
   "== input-text-3.html input-text-3-ref.html",
   "== textarea-1.html textarea-1-ref.html",
   "== textarea-2.html textarea-2-ref.html",
   "== textarea-3.html textarea-3-ref.html",
   "== css-transform-1.html css-transform-1-ref.html",
   "== css-transform-2.html css-transform-2-ref.html",
   "== container-with-clamping.html container-with-clamping-ref.html",
+  "!= video-1.html about:blank", // crashtest
 ];
 
 // Maintain a reference count of how many things we're waiting for until
 // we can say the tests are done.
 var gDelayCount = 0;
 function AddFinishDependency()
   { ++gDelayCount; }
 function RemoveFinishDependency()
--- a/layout/generic/nsHTMLReflowMetrics.h
+++ b/layout/generic/nsHTMLReflowMetrics.h
@@ -66,21 +66,21 @@ enum nsOverflowType { eVisualOverflow, e
   for (nsOverflowType var_ = nsOverflowType(0); var_ < 2;                     \
        var_ = nsOverflowType(var_ + 1))
 
 struct nsOverflowAreas {
 private:
   nsRect mRects[2];
 public:
   nsRect& Overflow(size_t aIndex) {
-    NS_ASSERTION(0 <= aIndex && aIndex < 2, "index out of range");
+    NS_ASSERTION(aIndex < 2, "index out of range");
     return mRects[aIndex];
   }
   const nsRect& Overflow(size_t aIndex) const {
-    NS_ASSERTION(0 <= aIndex && aIndex < 2, "index out of range");
+    NS_ASSERTION(aIndex < 2, "index out of range");
     return mRects[aIndex];
   }
 
   nsRect& VisualOverflow() { return mRects[eVisualOverflow]; }
   const nsRect& VisualOverflow() const { return mRects[eVisualOverflow]; }
 
   nsRect& ScrollableOverflow() { return mRects[eScrollableOverflow]; }
   const nsRect& ScrollableOverflow() const { return mRects[eScrollableOverflow]; }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/font-default.html
@@ -0,0 +1,12 @@
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+div {
+}
+</style>
+</head>
+<body>
+<div>Hello world 123</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/font-download.html
@@ -0,0 +1,17 @@
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+@font-face {
+  font-family: foo;
+  src: url(../fonts/DejaVuSansMono.woff);
+}
+div {
+  font-family: foo;
+}
+</style>
+</head>
+<body>
+<div>Hello world 123</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/font-sans-serif.html
@@ -0,0 +1,13 @@
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+div {
+  font-family: sans-serif;
+}
+</style>
+</head>
+<body>
+<div>Hello world 123</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/font-serif.html
@@ -0,0 +1,13 @@
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+div {
+  font-family: serif;
+}
+</style>
+</head>
+<body>
+<div>Hello world 123</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/font-size-16.html
@@ -0,0 +1,13 @@
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+div {
+  font-size: 16px;
+}
+</style>
+</head>
+<body>
+<div>Hello world 123</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/font-size-24.html
@@ -0,0 +1,13 @@
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<style type="text/css">
+div {
+  font-size: 24px;
+}
+</style>
+</head>
+<body>
+<div>Hello world 123</div>
+</body>
+</html>
--- a/layout/reftests/reftest-sanity/reftest.list
+++ b/layout/reftests/reftest-sanity/reftest.list
@@ -101,8 +101,31 @@ skip-if(!browserIsRemote) == test-displa
 
 # reftest syntax: require-or
 require-or(unrecognizedCondition,skip) script scripttest-fail.html
 require-or(true&&unrecognizedCondition,skip) script scripttest-fail.html
 require-or(unrecognizedCondition&&true,skip) script scripttest-fail.html
 require-or(unrecognizedCondition,fails) script scripttest-fail.html
 require-or(true,fails) script scripttest-pass.html
 require-or(true&&true,fails) script scripttest-pass.html
+
+# tests for pref(...) syntax in manifest, including "fails" examples with incorrect prefs
+# a boolean pref
+pref(gfx.downloadable_fonts.enabled,true) HTTP(..) != font-download.html font-default.html
+pref(gfx.downloadable_fonts.enabled,false) HTTP(..) == font-download.html font-default.html
+fails pref(gfx.downloadable_fonts.enabled,0) HTTP(..) == font-download.html font-default.html
+fails pref(gfx.downloadable_fonts.enabled,"foo") HTTP(..) == font-download.html font-default.html
+# a non-existent pref
+fails pref(not.a.real.pref.name,1) == font-download.html font-default.html
+# an integer pref
+pref(font.size.variable.x-western,16) == font-size-16.html font-default.html
+pref(font.size.variable.x-western,16) != font-size-24.html font-default.html
+pref(font.size.variable.x-western,24) == font-size-24.html font-default.html
+pref(font.size.variable.x-western,24) != font-size-16.html font-default.html
+fails pref(font.size.variable.x-western,false) == font-size-16.html font-default.html
+fails pref(font.size.variable.x-western,"foo") == font-size-16.html font-default.html
+# a string pref
+pref(font.default.x-western,"serif") == font-serif.html font-default.html
+pref(font.default.x-western,"serif") != font-sans-serif.html font-default.html
+pref(font.default.x-western,"sans-serif") == font-sans-serif.html font-default.html
+pref(font.default.x-western,"sans-serif") != font-serif.html font-default.html
+fails pref(font.default.x-western,true) == font-serif.html font-default.html
+fails pref(font.default.x-western,0) == font-serif.html font-default.html
--- a/layout/tools/reftest/README.txt
+++ b/layout/tools/reftest/README.txt
@@ -47,17 +47,17 @@ 1. Inclusion of another manifest
    combined by using the last matching failure type listed.  However, 
    the failure type on a manifest is combined with the failure type on 
    the test (or on a nested manifest) with the rule that the last in the
    following list wins:  fails, random, skip.  (In other words, skip 
    always wins, and random beats fails.)
 
 2. A test item
 
-   <failure-type>* [<http>] <type> <url> <url_ref>
+   <failure-type>* <preference>* [<http>] <type> <url> <url_ref>
 
    where
 
    a. <failure-type> (optional) is one of the following:
 
       fails  The test passes if the images of the two renderings DO NOT
              meet the conditions specified in the <type>.
 
@@ -141,17 +141,32 @@ 2. A test item
       They are evaluated in a sandbox in which a limited set of
       variables are defined.  See the BuildConditionSandbox function in
       layout/tools/reftest.js for details.
 
       Examples of using conditions:
           fails-if(winWidget) == test reference
           asserts-if(cocoaWidget,2) load crashtest
 
-   b. <http>, if present, is one of the strings (sans quotes) "HTTP" or
+   b. <pref-setting> (optional) is a string of the form
+
+          pref(<name>,<value>)
+
+      where <name> is the name of a preference setting, as seen in
+      about:config, and <value> is the value to which this preference should
+      be set. <value> may be a boolean (true/false), an integer, or a
+      quoted string *without spaces*, according to the type of the preference.
+
+      The preference will be set to the specified value prior to rendering
+      the test and reference canvases, and will be restored afterwards so
+      that following tests are not affected. Note that this feature is only
+      useful for "live" preferences that take effect immediately, without
+      requiring a browser restart.
+
+   c. <http>, if present, is one of the strings (sans quotes) "HTTP" or
       "HTTP(..)" or "HTTP(../..)" or "HTTP(../../..)", etc. , indicating that
       the test should be run over an HTTP server because it requires certain
       HTTP headers or a particular HTTP status.  (Don't use this if your test
       doesn't require this functionality, because it unnecessarily slows down
       the test.)
 
       With "HTTP", HTTP tests have the restriction that any resource an HTTP
       test accesses must be accessed using a relative URL, and the test and
@@ -200,17 +215,17 @@ 2. A test item
         var outputStream = response.bodyOutputStream;
         // ...anything else you want to do, synchronously...
       }
 
       For more details on exactly which functions and properties are available
       on request/response in handleRequest, see the nsIHttpRe(quest|sponse)
       definitions in <netwerk/test/httpserver/nsIHttpServer.idl>.
 
-   c. <type> is one of the following:
+   d. <type> is one of the following:
 
       ==     The test passes if the images of the two renderings are the
              SAME.
       !=     The test passes if the images of the two renderings are 
              DIFFERENT.
       load   The test passes unconditionally if the page loads.  url_ref
              must be omitted, and the test cannot be marked as fails or
              random.  (Used to test for crashes, hangs, assertions, and
@@ -228,20 +243,20 @@ 2. A test item
              otherwise it returns false.
 
              testDescription() returns a string describing the test
              result.
 
              url_ref must be omitted. The test may be marked as fails or
              random. (Used to test the JavaScript Engine.)
 
-   d. <url> is either a relative file path or an absolute URL for the
+   e. <url> is either a relative file path or an absolute URL for the
       test page
 
-   e. <url_ref> is either a relative file path or an absolute URL for
+   f. <url_ref> is either a relative file path or an absolute URL for
       the reference page
 
    The only difference between <url> and <url_ref> is that results of
    the test are reported using <url> only.
 
 3. Specification of a url prefix
 
    url-prefix <string>
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -145,16 +145,23 @@ const TYPE_SCRIPT = 'script'; // test co
 // FIXME: In the future, we may also want to use this rule for combining
 // statuses that are on the same line (rather than making the last one
 // win).
 const EXPECTED_PASS = 0;
 const EXPECTED_FAIL = 1;
 const EXPECTED_RANDOM = 2;
 const EXPECTED_DEATH = 3;  // test must be skipped to avoid e.g. crash/hang
 
+// types of preference value we might want to set for a specific test
+const PREF_BOOLEAN = 0;
+const PREF_STRING  = 1;
+const PREF_INTEGER = 2;
+
+var gPrefsToRestore = [];
+
 const gProtocolRE = /^\w+:/;
 
 var HTTP_SERVER_PORT = 4444;
 const HTTP_SERVER_PORTS_TO_TRY = 50;
 
 // whether to run slow tests or not
 var gRunSlowTests = true;
 
@@ -676,18 +683,19 @@ function ReadManifest(aURL, inherited_st
         }
 
         var expected_status = EXPECTED_PASS;
         var allow_silent_fail = false;
         var minAsserts = 0;
         var maxAsserts = 0;
         var needs_focus = false;
         var slow = false;
+        var prefSettings = [];
         
-        while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail)/)) {
+        while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref)/)) {
             var item = items.shift();
             var stat;
             var cond;
             var m = item.match(/^(fails|random|skip|silentfail)-if(\(.*\))$/);
             if (m) {
                 stat = m[1];
                 // Note: m[2] contains the parentheses, and we want them.
                 cond = Components.utils.evalInSandbox(m[2], sandbox);
@@ -739,16 +747,34 @@ function ReadManifest(aURL, inherited_st
                 }
             } else if ((m = item.match(/^slow-if\((.*?)\)$/))) {
                 cond = false;
                 if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox))
                     slow = true;
             } else if (item == "silentfail") {
                 cond = false;
                 allow_silent_fail = true;
+            } else if ((m = item.match(/^pref\((.+?),(.*)\)$/))) {
+                cond = false;
+                var prefName = m[1];
+                var prefVal = Components.utils.evalInSandbox("(" + m[2] + ")", sandbox);
+                var prefType;
+                var valType = typeof(prefVal);
+                if (valType == "boolean") {
+                    prefType = PREF_BOOLEAN;
+                } else if (valType == "string") {
+                    prefType = PREF_STRING;
+                } else if (valType == "number" && (parseInt(prefVal) == prefVal)) {
+                    prefType = PREF_INTEGER;
+                } else {
+                    throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo;
+                }
+                prefSettings.push( { name: prefName,
+                                     type: prefType,
+                                     value: prefVal } );
             } else {
                 throw "Error 1 in manifest file " + aURL.spec + " line " + lineNo;
             }
 
             if (cond) {
                 if (stat == "fails") {
                     expected_status = EXPECTED_FAIL;
                 } else if (stat == "random") {
@@ -817,16 +843,17 @@ function ReadManifest(aURL, inherited_st
             gURLs.push( { type: TYPE_LOAD,
                           expected: expected_status,
                           allowSilentFail: allow_silent_fail,
                           prettyPath: prettyPath,
                           minAsserts: minAsserts,
                           maxAsserts: maxAsserts,
                           needsFocus: needs_focus,
                           slow: slow,
+                          prefSettings: prefSettings,
                           url1: testURI,
                           url2: null } );
         } else if (items[0] == TYPE_SCRIPT) {
             if (items.length != 2)
                 throw "Error 4 in manifest file " + aURL.spec + " line " + lineNo;
             var [testURI] = runHttp
                             ? ServeFiles(aURL, httpDepth,
                                          listURL, [items[1]])
@@ -839,16 +866,17 @@ function ReadManifest(aURL, inherited_st
             gURLs.push( { type: TYPE_SCRIPT,
                           expected: expected_status,
                           allowSilentFail: allow_silent_fail,
                           prettyPath: prettyPath,
                           minAsserts: minAsserts,
                           maxAsserts: maxAsserts,
                           needsFocus: needs_focus,
                           slow: slow,
+                          prefSettings: prefSettings,
                           url1: testURI,
                           url2: null } );
         } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL) {
             if (items.length != 3)
                 throw "Error 5 in manifest file " + aURL.spec + " line " + lineNo;
             var [testURI, refURI] = runHttp
                                   ? ServeFiles(aURL, httpDepth,
                                                listURL, [items[1], items[2]])
@@ -864,16 +892,17 @@ function ReadManifest(aURL, inherited_st
             gURLs.push( { type: items[0],
                           expected: expected_status,
                           allowSilentFail: allow_silent_fail,
                           prettyPath: prettyPath,
                           minAsserts: minAsserts,
                           maxAsserts: maxAsserts,
                           needsFocus: needs_focus,
                           slow: slow,
+                          prefSettings: prefSettings,
                           url1: testURI,
                           url2: refURI } );
         } else {
             throw "Error 6 in manifest file " + aURL.spec + " line " + lineNo;
         }
     }
 }
 
@@ -892,17 +921,18 @@ function AddURIUseCount(uri)
 
 function BuildUseCounts()
 {
     gURIUseCounts = {};
     for (var i = 0; i < gURLs.length; ++i) {
         var url = gURLs[i];
         if (url.expected != EXPECTED_DEATH &&
             (url.type == TYPE_REFTEST_EQUAL ||
-             url.type == TYPE_REFTEST_NOTEQUAL)) {
+             url.type == TYPE_REFTEST_NOTEQUAL) &&
+            url.prefSettings.length == 0) {
             AddURIUseCount(gURLs[i].url1);
             AddURIUseCount(gURLs[i].url2);
         }
     }
 }
 
 function ServeFiles(manifestURL, depth, aURL, files)
 {
@@ -963,31 +993,104 @@ function Focus()
     }
     return true;
 }
 
 function StartCurrentTest()
 {
     gTestLog = [];
 
+    RestoreChangedPreferences();
+
     // make sure we don't run tests that are expected to kill the browser
     while (gURLs.length > 0) {
         var test = gURLs[0];
         if (test.expected == EXPECTED_DEATH) {
             ++gTestResults.Skip;
             gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIP)\n");
             gURLs.shift();
         } else if (test.needsFocus && !Focus()) {
             ++gTestResults.Skip;
             gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIPPED; COULDN'T GET FOCUS)\n");
             gURLs.shift();
         } else if (test.slow && !gRunSlowTests) {
             ++gTestResults.Slow;
             gDumpLog("REFTEST TEST-KNOWN-SLOW | " + test.url1.spec + " | (SLOW)\n");
             gURLs.shift();
+        } else if (gURLs[0].prefSettings.length > 0) {
+            var prefs = Components.classes["@mozilla.org/preferences-service;1"].
+                        getService(Components.interfaces.nsIPrefBranch2);
+            var badPref = undefined;
+            try {
+                gURLs[0].prefSettings.forEach(function(ps) {
+                    var oldVal;
+                    if (ps.type == PREF_BOOLEAN) {
+                        try {
+                            oldVal = prefs.getBoolPref(ps.name);
+                        } catch (e) {
+                            badPref = "boolean preference '" + ps.name + "'";
+                            throw "bad pref";
+                        }
+                    } else if (ps.type == PREF_STRING) {
+                        try {
+                            oldVal = prefs.getCharPref(ps.name);
+                        } catch (e) {
+                            badPref = "string preference '" + ps.name + "'";
+                            throw "bad pref";
+                        }
+                    } else if (ps.type == PREF_INTEGER) {
+                        try {
+                            oldVal = prefs.getIntPref(ps.name);
+                        } catch (e) {
+                            badPref = "integer preference '" + ps.name + "'";
+                            throw "bad pref";
+                        }
+                    } else {
+                        throw "internal error - unknown preference type";
+                    }
+                    if (oldVal != ps.value) {
+                        gPrefsToRestore.push( { name: ps.name,
+                                                type: ps.type,
+                                                value: oldVal } );
+                        var value = ps.value;
+                        if (ps.type == PREF_BOOLEAN) {
+                            prefs.setBoolPref(ps.name, value);
+                        } else if (ps.type == PREF_STRING) {
+                            prefs.setCharPref(ps.name, value);
+                            value = '"' + value + '"';
+                        } else if (ps.type == PREF_INTEGER) {
+                            prefs.setIntPref(ps.name, value);
+                        }
+                        gDumpLog("SET PREFERENCE pref(" + ps.name + "," + value + ")\n");
+                    }
+                });
+            } catch (e) {
+                if (e == "bad pref") {
+                    if (test.expected == EXPECTED_FAIL) {
+                        gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec +
+                                 " | (SKIPPED; " + badPref + " not known or wrong type)\n");
+                        ++gTestResults.Skip;
+                    } else {
+                        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + test.url1.spec +
+                                 " | " + badPref + " not known or wrong type\n");
+                        ++gTestResults.UnexpectedFail;
+                    }
+                } else {
+                    throw e;
+                }
+            }
+            if (badPref != undefined) {
+                // undo anything we changed
+                RestoreChangedPreferences();
+
+                // skip the test that had a bad preference
+                gURLs.shift();
+            } else {
+                break;
+            }
         } else {
             break;
         }
     }
 
     if (gURLs.length == 0) {
         DoneTests();
     }
@@ -999,17 +1102,18 @@ function StartCurrentTest()
     }
 }
 
 function StartCurrentURI(aState)
 {
     gState = aState;
     gCurrentURL = gURLs[0]["url" + aState].spec;
 
-    if (gURICanvases[gCurrentURL] &&
+    if (gURLs[0].prefSettings.length == 0 &&
+        gURICanvases[gCurrentURL] &&
         (gURLs[0].type == TYPE_REFTEST_EQUAL ||
          gURLs[0].type == TYPE_REFTEST_NOTEQUAL) &&
         gURLs[0].maxAsserts == 0) {
         // Pretend the document loaded --- RecordResult will notice
         // there's already a canvas for this URL
         gContainingWindow.setTimeout(RecordResult, 0);
     } else {
         var currentTest = gTotalTests - gURLs.length;
@@ -1259,17 +1363,18 @@ function RecordResult(testRunTime, error
         if (anyFailed && expected == EXPECTED_PASS) {
             FlushTestLog();
         }
 
         FinishTestItem();
         return;
     }
 
-    if (gURICanvases[gCurrentURL]) {
+    if (gURLs[0].prefSettings.length == 0 &&
+        gURICanvases[gCurrentURL]) {
         gCurrentCanvas = gURICanvases[gCurrentURL];
     }
     if (gCurrentCanvas == null) {
         gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | program error managing snapshots\n");
         ++gTestResults.Exception;
     }
     if (gState == 1) {
         gCanvas1 = gCurrentCanvas;
@@ -1338,18 +1443,20 @@ function RecordResult(testRunTime, error
                     gDumpLog("REFTEST   IMAGE: " + gCanvas1.toDataURL() + "\n");
                 }
             }
 
             if (!test_passed && expected == EXPECTED_PASS) {
                 FlushTestLog();
             }
 
-            UpdateCanvasCache(gURLs[0].url1, gCanvas1);
-            UpdateCanvasCache(gURLs[0].url2, gCanvas2);
+            if (gURLs[0].prefSettings.length == 0) {
+                UpdateCanvasCache(gURLs[0].url1, gCanvas1);
+                UpdateCanvasCache(gURLs[0].url2, gCanvas2);
+            }
 
             CleanUpCrashDumpFiles();
             FinishTestItem();
             break;
         default:
             throw "Unexpected state.";
     }
 }
@@ -1469,16 +1576,37 @@ function DoAssertionCheck(numAsserts)
 }
 
 function ResetRenderingState()
 {
     SendResetRenderingState();
     // We would want to clear any viewconfig here, if we add support for it
 }
 
+function RestoreChangedPreferences()
+{
+    if (gPrefsToRestore.length > 0) {
+        var prefs = Components.classes["@mozilla.org/preferences-service;1"].
+                    getService(Components.interfaces.nsIPrefBranch2);
+        gPrefsToRestore.forEach(function(ps) {
+            var value = ps.value;
+            if (ps.type == PREF_BOOLEAN) {
+                prefs.setBoolPref(ps.name, value);
+            } else if (ps.type == PREF_STRING) {
+                prefs.setCharPref(ps.name, value);
+                value = '"' + value + '"';
+            } else if (ps.type == PREF_INTEGER) {
+                prefs.setIntPref(ps.name, value);
+            }
+            gDumpLog("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")\n");
+        });
+        gPrefsToRestore = [];
+    }
+}
+
 function RegisterMessageListenersAndLoadContentScript()
 {
     gBrowserMessageManager.addMessageListener(
         "reftest:AssertionCount",
         function (m) { RecvAssertionCount(m.json.count); }
     );
     gBrowserMessageManager.addMessageListener(
         "reftest:ContentReady",
--- a/mobile/xul/installer/package-manifest.in
+++ b/mobile/xul/installer/package-manifest.in
@@ -149,16 +149,17 @@
 @BINPATH@/components/content_xtf.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_telephony.xpt
+@BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
@@ -393,16 +394,18 @@
 @BINPATH@/components/messageWakeupService.manifest
 @BINPATH@/components/nsFilePicker.js
 @BINPATH@/components/nsFilePicker.manifest
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/nsTelephonyWorker.manifest
 @BINPATH@/components/nsTelephonyWorker.js
 @BINPATH@/components/Telephony.manifest
 @BINPATH@/components/Telephony.js
+@BINPATH@/components/nsWifiWorker.js
+@BINPATH@/components/nsWifiWorker.manifest
 #endif
 #ifdef XP_MACOSX
 @BINPATH@/components/libalerts_s.dylib
 #endif
 #ifdef MOZ_ENABLE_DBUS
 @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
 #endif
 @BINPATH@/components/nsINIProcessor.manifest
--- a/storage/test/test_AsXXX_helpers.cpp
+++ b/storage/test/test_AsXXX_helpers.cpp
@@ -99,20 +99,22 @@ test_asyncNULLFallback()
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   nsCOMPtr<mozIStorageAsyncStatement> stmt;
   (void)db->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "SELECT NULL"
   ), getter_AddRefs(stmt));
 
+  nsCOMPtr<mozIStoragePendingStatement> pendingStmt;
+  do_check_true(NS_SUCCEEDED(stmt->ExecuteAsync(nsnull, getter_AddRefs(pendingStmt))));
+  do_check_true(pendingStmt);
+  stmt->Finalize();
   nsRefPtr<Spinner> asyncSpin(new Spinner());
-  nsCOMPtr<mozIStoragePendingStatement> pendingStmt;
-  do_check_true(NS_SUCCEEDED(stmt->ExecuteAsync(asyncSpin, getter_AddRefs(pendingStmt))));
-  do_check_true(pendingStmt);
+  db->AsyncClose(asyncSpin);
   asyncSpin->SpinUntilCompleted();
 
 }
 
 void (*gTests[])(void) = {
   test_NULLFallback
 , test_asyncNULLFallback
 };
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -329,17 +329,26 @@ function _execute_test() {
   } catch (e) {
     _passed = false;
     // do_check failures are already logged and set _quit to true and throw
     // NS_ERROR_ABORT. If both of those are true it is likely this exception
     // has already been logged so there is no need to log it again. It's
     // possible that this will mask an NS_ERROR_ABORT that happens after a
     // do_check failure though.
     if (!_quit || e != Components.results.NS_ERROR_ABORT) {
-      msg = "TEST-UNEXPECTED-FAIL | (xpcshell/head.js) | " + e;
+      msg = "TEST-UNEXPECTED-FAIL | ";
+      if ('fileName' in e) {
+        msg += e.fileName;
+        if ('lineNumber' in e) {
+          msg += ":" + e.lineNumber;
+        }
+      } else {
+        msg += "xpcshell/head.js";
+      }
+      msg += " | " + e;
       if (e.stack) {
         _dump(msg + " - See following stack:\n");
         _dump_exception_stack(e.stack);
       }
       else {
         _dump(msg + "\n");
       }
     }
--- a/toolkit/components/downloads/test/schema_migration/test_migration_to_2.js
+++ b/toolkit/components/downloads/test/schema_migration/test_migration_to_2.js
@@ -69,13 +69,13 @@ function run_test()
   do_check_eq("381603.patch", stmt.getString(0));
   do_check_eq("https://bugzilla.mozilla.org/attachment.cgi?id=266520",
               stmt.getUTF8String(1));
   do_check_eq("file:///Users/sdwilsh/Desktop/381603.patch",
               stmt.getUTF8String(2));
   do_check_eq(1180493839859230, stmt.getInt64(3));
   do_check_eq(1180493839859230, stmt.getInt64(4));
   do_check_eq(1, stmt.getInt32(5));
-  stmt.reset();
+  stmt.finalize();
 
   cleanup();
 }
 
--- a/toolkit/components/downloads/test/schema_migration/test_migration_to_3.js
+++ b/toolkit/components/downloads/test/schema_migration/test_migration_to_3.js
@@ -49,29 +49,30 @@ function run_test()
   var dbConn = dm.DBConnection;
   var stmt = null;
 
   // check schema version
   do_check_true(dbConn.schemaVersion >= 3);
 
   // Check that the column exists (statement should not throw)
   stmt = dbConn.createStatement("SELECT referrer FROM moz_downloads");
+  stmt.finalize();
 
   // now we check the entries
   stmt = dbConn.createStatement(
     "SELECT name, source, target, startTime, endTime, state, referrer " +
     "FROM moz_downloads " +
     "WHERE id = 2");
   stmt.executeStep();
   do_check_eq("381603.patch", stmt.getString(0));
   do_check_eq("https://bugzilla.mozilla.org/attachment.cgi?id=266520",
               stmt.getUTF8String(1));
   do_check_eq("file:///Users/sdwilsh/Desktop/381603.patch",
               stmt.getUTF8String(2));
   do_check_eq(1180493839859230, stmt.getInt64(3));
   do_check_eq(1180493839859230, stmt.getInt64(4));
   do_check_eq(1, stmt.getInt32(5));
   do_check_true(stmt.getIsNull(6));
-  stmt.reset();
+  stmt.finalize();
 
   cleanup();
 }
 
--- a/toolkit/components/downloads/test/schema_migration/test_migration_to_4.js
+++ b/toolkit/components/downloads/test/schema_migration/test_migration_to_4.js
@@ -50,16 +50,17 @@ function run_test()
   var dbConn = dm.DBConnection;
   var stmt = null;
 
   // check schema version
   do_check_true(dbConn.schemaVersion >= 4);
 
   // Check that the column exists (statement should not throw)
   stmt = dbConn.createStatement("SELECT entityID FROM moz_downloads");
+  stmt.finalize();
 
   // now we check the entries
   stmt = dbConn.createStatement(
     "SELECT name, source, target, startTime, endTime, state, referrer, entityID " +
     "FROM moz_downloads " +
     "WHERE id = 27");
   stmt.executeStep();
   do_check_eq("Firefox 2.0.0.6.dmg", stmt.getString(0));
@@ -67,13 +68,13 @@ function run_test()
               stmt.getUTF8String(1));
   do_check_eq("file:///Users/sdwilsh/Desktop/Firefox%202.0.0.6.dmg",
               stmt.getUTF8String(2));
   do_check_eq(1187390974170783, stmt.getInt64(3));
   do_check_eq(1187391001257446, stmt.getInt64(4));
   do_check_eq(1, stmt.getInt32(5));
   do_check_eq("http://www.mozilla.com/en-US/products/download.html?product=firefox-2.0.0.6&os=osx&lang=en-US",stmt.getUTF8String(6));
   do_check_true(stmt.getIsNull(7));
-  stmt.reset();
+  stmt.finalize();
 
   cleanup();
 }
 
--- a/toolkit/components/downloads/test/schema_migration/test_migration_to_5.js
+++ b/toolkit/components/downloads/test/schema_migration/test_migration_to_5.js
@@ -66,12 +66,12 @@ function run_test()
   do_check_eq("file:///Users/sdwilsh/Desktop/Firefox%202.0.0.6.dmg",
               stmt.getUTF8String(2));
   do_check_eq(1187390974170783, stmt.getInt64(3));
   do_check_eq(1187391001257446, stmt.getInt64(4));
   do_check_eq(1, stmt.getInt32(5));
   do_check_eq("http://www.mozilla.com/en-US/products/download.html?product=firefox-2.0.0.6&os=osx&lang=en-US",stmt.getUTF8String(6));
   do_check_true(stmt.getIsNull(7));
   do_check_true(stmt.getIsNull(8));
-  stmt.reset();
+  stmt.finalize();
 
   cleanup();
 }
--- a/toolkit/components/downloads/test/schema_migration/test_migration_to_6.js
+++ b/toolkit/components/downloads/test/schema_migration/test_migration_to_6.js
@@ -68,12 +68,12 @@ function run_test()
   do_check_eq(1187390974170783, stmt.getInt64(3));
   do_check_eq(1187391001257446, stmt.getInt64(4));
   do_check_eq(1, stmt.getInt32(5));
   do_check_eq("http://www.mozilla.com/en-US/products/download.html?product=firefox-2.0.0.6&os=osx&lang=en-US",stmt.getUTF8String(6));
   do_check_true(stmt.getIsNull(7));
   do_check_true(stmt.getIsNull(8));
   do_check_eq(0, stmt.getInt64(9));
   do_check_eq(-1, stmt.getInt64(10));
-  stmt.reset();
+  stmt.finalize();
 
   cleanup();
 }
--- a/toolkit/components/downloads/test/unit/head_download_manager.js
+++ b/toolkit/components/downloads/test/unit/head_download_manager.js
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 // This file tests the download manager backend
 
 do_load_httpd_js();
 do_get_profile();
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
 
 var downloadUtils = { };
 XPCOMUtils.defineLazyServiceGetter(downloadUtils,
                                    "downloadManager",
                                    "@mozilla.org/download-manager;1",
                                    Ci.nsIDownloadManager);
 
 function createURI(aObj)
@@ -183,8 +184,12 @@ function getDownloadListener()
 
 XPCOMUtils.defineLazyGetter(this, "Services", function() {
   Cu.import("resource://gre/modules/Services.jsm");
   return Services;
 });
 
 // Disable alert service notifications
 Services.prefs.setBoolPref("browser.download.manager.showAlertOnComplete", false);
+
+do_register_cleanup(function() {
+  Services.obs.notifyObservers(null, "quit-application", null);
+});
--- a/toolkit/components/downloads/test/unit/test_removeDownloadsByTimeframe.js
+++ b/toolkit/components/downloads/test/unit/test_removeDownloadsByTimeframe.js
@@ -76,16 +76,17 @@ function add_download_to_db(aStartTimeIn
     "INSERT INTO moz_downloads (id, startTime, endTime, state) " +
     "VALUES (:id, :startTime, :endTime, :state)"
   );
   stmt.params.id = id;
   stmt.params.startTime = aStartTimeInRange ? START_TIME + 1 : START_TIME - 1;
   stmt.params.endTime = aEndTimeInRange ? END_TIME - 1 : END_TIME + 1;
   stmt.params.state = aState;
   stmt.execute();
+  stmt.finalize();
 
   return id++;
 }
 
 /**
  * Checks to see the downloads with the specified id exist or not.
  *
  * @param aIDs
@@ -103,16 +104,17 @@ function check_existence(aIDs, aExpected
   );
 
   let checkFunc = aExpected ? do_check_true : do_check_false;
   for (let i = 0; i < aIDs.length; i++) {
     stmt.params.id = aIDs[i];
     checkFunc(stmt.executeStep());
     stmt.reset();
   }
+  stmt.finalize();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Test Functions
 
 function test_download_start_in_range()
 {
   let id = add_download_to_db(true, false, DOWNLOAD_FINISHED);
--- a/toolkit/components/satchel/nsFormHistory.js
+++ b/toolkit/components/satchel/nsFormHistory.js
@@ -132,17 +132,16 @@ FormHistory.prototype = {
         this.dbStmts = {};
 
         this.messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
                               getService(Ci.nsIChromeFrameMessageManager);
         this.messageManager.loadFrameScript("chrome://satchel/content/formSubmitListener.js", true);
         this.messageManager.addMessageListener("FormHistory:FormSubmitEntries", this);
 
         // Add observers
-        Services.obs.addObserver(this, "profile-change-teardown", true);
         Services.obs.addObserver(this, "profile-before-change", true);
         Services.obs.addObserver(this, "idle-daily", true);
         Services.obs.addObserver(this, "formhistory-expire-now", true);
     },
 
     /* ---- message listener ---- */
 
 
@@ -398,20 +397,17 @@ FormHistory.prototype = {
         case "nsPref:changed":
             this.updatePrefs();
             break;
         case "idle-daily":
         case "formhistory-expire-now":
             this.expireOldEntries();
             break;
         case "profile-before-change":
-            // FIXME (bug 696486): close the connection in here.
-            break;
-        case "profile-change-teardown":
-            this._dbFinalize();
+            this._dbClose();
             break;
         default:
             this.log("Oops! Unexpected notification: " + topic);
             break;
         }
     },
 
 
@@ -864,25 +860,32 @@ FormHistory.prototype = {
             stmt.finalize();
             return true;
         } catch (e) {
             return false;
         }
     },
 
     /**
-     * _dbFinalize
+     * _dbClose
      *
-     * Finalize all statements to allow closing the connection correctly.
+     * Finalize all statements and close the connection.
      */
-    _dbFinalize : function FH__dbFinalize() {
+    _dbClose : function FH__dbClose() {
         for each (let stmt in this.dbStmts) {
             stmt.finalize();
         }
         this.dbStmts = {};
+        if (this.dbConnection !== undefined) {
+            try {
+                this.dbConnection.close();
+            } catch (e) {
+                Components.utils.reportError(e);
+            }
+        }
     },
 
     /*
      * dbCleanup
      *
      * Called when database creation fails. Finalizes database statements,
      * closes the database connection, deletes the database file.
      */
@@ -890,24 +893,15 @@ FormHistory.prototype = {
         this.log("Cleaning up DB file - close & remove & backup")
 
         // Create backup file
         let storage = Cc["@mozilla.org/storage/service;1"].
                       getService(Ci.mozIStorageService);
         let backupFile = this.dbFile.leafName + ".corrupt";
         storage.backupDatabaseFile(this.dbFile, backupFile);
 
-        this._dbFinalize();
-
-        if (this.dbConnection !== undefined) {
-            try {
-                this.dbConnection.close();
-            } catch (e) {
-                Components.utils.reportError(e);
-            }
-        }
-
+        this._dbClose();
         this.dbFile.remove(false);
     }
 };
 
 let component = [FormHistory];
 var NSGetFactory = XPCOMUtils.generateNSGetFactory(component);
--- a/toolkit/content/tests/unit/test_privatebrowsing_downloadLastDir_c.js
+++ b/toolkit/content/tests/unit/test_privatebrowsing_downloadLastDir_c.js
@@ -148,11 +148,15 @@ function run_test()
   // file picker should start with browser.download.lastDir as set before entering the private browsing mode
   do_check_eq(fp.displayDirectory.path, dir1.path);
   // browser.download.lastDir should be modified after leaving the private browsing mode
   do_check_eq(prefs.getComplexValue("lastDir", Ci.nsILocalFile).path, dir3.path);
   // gDownloadLastDir should be usable after leaving the private browsing mode
   do_check_eq(gDownloadLastDir.file.path, dir3.path);
 
   // cleanup
+  Cc["@mozilla.org/observer-service;1"]
+    .getService(Ci.nsIObserverService)
+    .notifyObservers(null, "quit-application", null);
+
   prefsService.clearUserPref("browser.privatebrowsing.keep_current_session");
   [dir1, dir2, dir3].forEach(function(dir) dir.remove(true));
 }
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -347,21 +347,22 @@ INNER_MAKE_PACKAGE	= \
     $(ZIP) -0 $(_ABS_DIST)/gecko.ap_ $(OMNIJAR_NAME)) && \
   rm -f $(_ABS_DIST)/gecko.apk && \
   $(APKBUILDER) $(_ABS_DIST)/gecko.apk -v $(APKBUILDER_FLAGS) -z $(_ABS_DIST)/gecko.ap_ -f $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/classes.dex && \
   cp $(_ABS_DIST)/gecko.apk $(_ABS_DIST)/gecko-unsigned-unaligned.apk && \
   $(JARSIGNER) $(_ABS_DIST)/gecko.apk && \
   $(ZIPALIGN) -f -v 4 $(_ABS_DIST)/gecko.apk $(PACKAGE)
 INNER_UNMAKE_PACKAGE	= \
   mkdir $(MOZ_PKG_DIR) && \
-  cd $(MOZ_PKG_DIR) && \
+  pushd $(MOZ_PKG_DIR) && \
   $(UNZIP) $(UNPACKAGE) && \
   mv lib/$(ABI_DIR)/libmozutils.so . && \
   mv lib/$(ABI_DIR)/*plugin-container* $(MOZ_CHILD_PROCESS_NAME) && \
-  rm -rf lib/$(ABI_DIR)
+  rm -rf lib/$(ABI_DIR) && \
+  popd
 endif
 ifeq ($(MOZ_PKG_FORMAT),DMG)
 ifndef _APPNAME
 _APPNAME = $(MOZ_MACBUNDLE_NAME)
 endif
 ifndef _BINPATH
 _BINPATH	= /$(_APPNAME)/Contents/MacOS
 endif # _BINPATH
--- a/toolkit/xre/nsSigHandlers.cpp
+++ b/toolkit/xre/nsSigHandlers.cpp
@@ -106,17 +106,17 @@ void
 ah_crap_handler(int signum)
 {
   printf("\nProgram %s (pid = %d) received signal %d.\n",
          _progname,
          getpid(),
          signum);
 
   printf("Stack:\n");
-  NS_StackWalk(PrintStackFrame, 2, nsnull);
+  NS_StackWalk(PrintStackFrame, 2, nsnull, 0);
 
   printf("Sleeping for %d seconds.\n",_gdb_sleep_duration);
   printf("Type 'gdb %s %d' to attach your debugger to this thread.\n",
          _progname,
          getpid());
 
   sleep(_gdb_sleep_duration);
 
--- a/tools/trace-malloc/lib/nsTraceMalloc.c
+++ b/tools/trace-malloc/lib/nsTraceMalloc.c
@@ -957,17 +957,17 @@ backtrace(tm_thread *t, int skip, int *i
 
     t->suppress_tracing++;
 
     if (!stacks_enabled) {
 #if defined(XP_MACOSX)
         /* Walk the stack, even if stacks_enabled is false. We do this to
            check if we must set immediate_abort. */
         info->entries = 0;
-        rv = NS_StackWalk(stack_callback, skip, info);
+        rv = NS_StackWalk(stack_callback, skip, info, 0);
         *immediate_abort = rv == NS_ERROR_UNEXPECTED;
         if (rv == NS_ERROR_UNEXPECTED || info->entries == 0) {
             t->suppress_tracing--;
             return NULL;
         }
 #endif
 
         /*
@@ -992,17 +992,17 @@ backtrace(tm_thread *t, int skip, int *i
          * (when loading a shared library).  So we can't be in tmlock during
          * this call.  For details, see
          * https://bugzilla.mozilla.org/show_bug.cgi?id=374829#c8
          */
 
         /* skip == 0 means |backtrace| should show up, so don't use skip + 1 */
         /* NB: this call is repeated below if the buffer is too small */
         info->entries = 0;
-        rv = NS_StackWalk(stack_callback, skip, info);
+        rv = NS_StackWalk(stack_callback, skip, info, 0);
         *immediate_abort = rv == NS_ERROR_UNEXPECTED;
         if (rv == NS_ERROR_UNEXPECTED || info->entries == 0) {
             t->suppress_tracing--;
             return NULL;
         }
 
         /*
          * To avoid allocating in stack_callback (which, on Windows, is
@@ -1016,17 +1016,17 @@ backtrace(tm_thread *t, int skip, int *i
                                    new_stack_buffer_size * sizeof(void*));
             if (!new_stack_buffer)
                 return NULL;
             info->buffer = new_stack_buffer;
             info->size = new_stack_buffer_size;
 
             /* and call NS_StackWalk again */
             info->entries = 0;
-            NS_StackWalk(stack_callback, skip, info);
+            NS_StackWalk(stack_callback, skip, info, 0);
 
             /* same stack */
             PR_ASSERT(info->entries * 2 == new_stack_buffer_size);
         }
     }
 
     TM_ENTER_LOCK(t);
 
--- a/xpcom/base/nsStackWalk.cpp
+++ b/xpcom/base/nsStackWalk.cpp
@@ -128,17 +128,17 @@ my_malloc_logger(uint32_t type, uintptr_
   if (once)
     return;
   once = true;
 
   // On Leopard dladdr returns the wrong value for "new_sem_from_pool". The
   // stack shows up as having two pthread_cond_wait$UNIX2003 frames.
   const char *name = OnSnowLeopardOrLater() ? "new_sem_from_pool" :
     "pthread_cond_wait$UNIX2003";
-  NS_StackWalk(stack_callback, 0, const_cast<char*>(name));
+  NS_StackWalk(stack_callback, 0, const_cast<char*>(name), 0);
 }
 
 void
 StackWalkInitCriticalAddress()
 {
   if(gCriticalAddress.mInit)
     return;
   gCriticalAddress.mInit = true;
@@ -797,37 +797,44 @@ WalkStackThread(void* aData)
  * chain in aBuffer. For this to work properly, the DLLs must be rebased
  * so that the address in the file agrees with the address in memory.
  * Otherwise StackWalk will return FALSE when it hits a frame in a DLL
  * whose in memory address doesn't match its in-file address.
  */
 
 EXPORT_XPCOM_API(nsresult)
 NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
-             void *aClosure)
+             void *aClosure, uintptr_t aThread)
 {
     MOZ_ASSERT(gCriticalAddress.mInit);
     HANDLE myProcess, myThread;
     DWORD walkerReturn;
     struct WalkStackData data;
 
     if (!EnsureImageHlpInitialized())
         return false;
 
+    HANDLE targetThread;
+    if (aThread) {
+        targetThread = reinterpret_cast<HANDLE> (aThread);
+    } else {
+        targetThread = ::GetCurrentThread();
+    }
+
     // Have to duplicate handle to get a real handle.
     if (!::DuplicateHandle(::GetCurrentProcess(),
                            ::GetCurrentProcess(),
                            ::GetCurrentProcess(),
                            &myProcess,
                            PROCESS_ALL_ACCESS, FALSE, 0)) {
         PrintError("DuplicateHandle (process)");
         return NS_ERROR_FAILURE;
     }
     if (!::DuplicateHandle(::GetCurrentProcess(),
-                           ::GetCurrentThread(),
+                           targetThread,
                            ::GetCurrentProcess(),
                            &myThread,
                            THREAD_ALL_ACCESS, FALSE, 0)) {
         PrintError("DuplicateHandle (thread)");
         ::CloseHandle(myProcess);
         return NS_ERROR_FAILURE;
     }
 
@@ -1476,19 +1483,20 @@ cswalkstack(struct frame *fp, int (*oper
 static void
 cs_operate(int (*operate_func)(void *, void *), void * usrarg)
 {
     cswalkstack(csgetframeptr(), operate_func, usrarg);
 }
 
 EXPORT_XPCOM_API(nsresult)
 NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
-             void *aClosure)
+             void *aClosure, uintptr_t aThread)
 {
     MOZ_ASSERT(gCriticalAddress.mInit);
+    MOZ_ASSERT(!aThread);
     struct my_user_args args;
 
     if (!initialized)
         myinit();
 
     args.callback = aCallback;
     args.skipFrames = aSkipFrames; /* XXX Not handled! */
     args.closure = aClosure;
@@ -1556,19 +1564,20 @@ NS_FormatCodeAddressDetails(void *aPC, c
 #endif
 
 #if HAVE___LIBC_STACK_END
 extern void *__libc_stack_end; // from ld-linux.so
 #endif
 
 EXPORT_XPCOM_API(nsresult)
 NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
-             void *aClosure)
+             void *aClosure, uintptr_t aThread)
 {
   MOZ_ASSERT(gCriticalAddress.mInit);
+  MOZ_ASSERT(!aThread);
   // Stack walking code courtesy Kipp's "leaky".
 
   // Get the frame pointer
   void **bp;
 #if defined(__i386) 
   __asm__( "movl %%ebp, %0" : "=g"(bp));
 #else
   // It would be nice if this worked uniformly, but at least on i386 and
@@ -1634,19 +1643,20 @@ unwind_callback (struct _Unwind_Context 
     }
     if (--info->skip < 0)
         (*info->callback)(pc, info->closure);
     return _URC_NO_REASON;
 }
 
 EXPORT_XPCOM_API(nsresult)
 NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
-             void *aClosure)
+             void *aClosure, uintptr_t aThread)
 {
     MOZ_ASSERT(gCriticalAddress.mInit);
+    MOZ_ASSERT(!aThread);
     unwind_info info;
     info.callback = aCallback;
     info.skip = aSkipFrames + 1;
     info.closure = aClosure;
 
     _Unwind_Reason_Code t = _Unwind_Backtrace(unwind_callback, &info);
     if (t != _URC_END_OF_STACK)
         return NS_ERROR_UNEXPECTED;
@@ -1712,19 +1722,20 @@ NS_FormatCodeAddressDetails(void *aPC, c
 }
 
 #endif
 
 #else // unsupported platform.
 
 EXPORT_XPCOM_API(nsresult)
 NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
-             void *aClosure)
+             void *aClosure, uintptr_t aThread)
 {
     MOZ_ASSERT(gCriticalAddress.mInit);
+    MOZ_ASSERT(!aThread);
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 EXPORT_XPCOM_API(nsresult)
 NS_DescribeCodeAddress(void *aPC, nsCodeAddressDetails *aDetails)
 {
     aDetails->library[0] = '\0';
     aDetails->loffset = 0;
--- a/xpcom/base/nsStackWalk.h
+++ b/xpcom/base/nsStackWalk.h
@@ -38,44 +38,49 @@
 /* API for getting a stack trace of the C/C++ stack on the current thread */
 
 #ifndef nsStackWalk_h_
 #define nsStackWalk_h_
 
 /* WARNING: This file is intended to be included from C or C++ files. */
 
 #include "nscore.h"
+#include <mozilla/StdInt.h>
 
 PR_BEGIN_EXTERN_C
 
 typedef void
 (* NS_WalkStackCallback)(void *aPC, void *aClosure);
 
 /**
  * Call aCallback for the C/C++ stack frames on the current thread, from
  * the caller of NS_StackWalk to main (or above).
  *
  * @param aCallback    Callback function, called once per frame.
  * @param aSkipFrames  Number of initial frames to skip.  0 means that
  *                     the first callback will be for the caller of
  *                     NS_StackWalk.
  * @param aClosure     Caller-supplied data passed through to aCallback.
+ * @param aThread      The thread for which the stack is to be retrieved.
+ *                     Passing null causes us to walk the stack of the
+ *                     current thread. On Windows, this is a thread HANDLE.
+ *                     It is currently not supported on any other platform.
  *
  * Returns NS_ERROR_NOT_IMPLEMENTED on platforms where it is
  * unimplemented.
  * Returns NS_ERROR_UNEXPECTED when the stack indicates that the thread
  * is in a very dangerous situation (e.g., holding sem_pool_lock in 
  * Mac OS X pthreads code). Callers should then bail out immediately.
  *
  * May skip some stack frames due to compiler optimizations or code
  * generation.
  */
 XPCOM_API(nsresult)
 NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
-             void *aClosure);
+             void *aClosure, uintptr_t aThread);
 
 typedef struct {
     /*
      * The name of the shared library or executable containing an
      * address and the address's offset within that library, or empty
      * string and zero if unknown.
      */
     char library[256];
--- a/xpcom/base/nsTraceRefcntImpl.cpp
+++ b/xpcom/base/nsTraceRefcntImpl.cpp
@@ -878,17 +878,17 @@ static void PrintStackFrame(void *aPC, v
   fputs(buf, stream);
 }
 
 }
 
 void
 nsTraceRefcntImpl::WalkTheStack(FILE* aStream)
 {
-  NS_StackWalk(PrintStackFrame, 2, aStream);
+  NS_StackWalk(PrintStackFrame, 2, aStream, 0);
 }
 
 //----------------------------------------------------------------------
 
 // This thing is exported by libstdc++
 // Yes, this is a gcc only hack
 #if defined(MOZ_DEMANGLE_SYMBOLS)
 #include <cxxabi.h>