Merge last green changeset of mozilla-inbound to mozilla-central
authorEd Morley <bmo@edmorley.co.uk>
Thu, 06 Oct 2011 16:25:34 +0100
changeset 78862 552e3737ab7cd3ceea7ff0bd6edbdc26fc9be74e
parent 78829 62ea504b378d32e3b10cb6358a5ae869285eb7e5 (current diff)
parent 78861 a256a4174461680b86dde326579763d8ed12dca7 (diff)
child 78863 737e0ebf68b25eb69df2ef884e4a26f72843b8dc
push id506
push userclegnitto@mozilla.com
push dateWed, 09 Nov 2011 02:03:18 +0000
treeherdermozilla-aurora@63587fc7bb93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone10.0a1
Merge last green changeset of mozilla-inbound to mozilla-central
--- a/Makefile.in
+++ b/Makefile.in
@@ -167,16 +167,17 @@ buildsymbols:
 ifdef MOZ_CRASHREPORTER
 ifdef USE_ELF_HACK
 	$(MAKE) -C $(MOZ_BUILD_APP)/installer elfhack
 endif
 	echo building symbol store
 	$(RM) -r $(DIST)/crashreporter-symbols
 	$(RM) "$(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip"
 	$(NSINSTALL) -D $(DIST)/crashreporter-symbols
+	OBJCOPY="$(OBJCOPY)" \
 	$(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py \
 	  $(MAKE_SYM_STORE_ARGS)                                          \
 	  $(foreach dir,$(SYM_STORE_SOURCE_DIRS),-s $(dir))               \
 	  $(DUMP_SYMS_BIN)                                                \
 	  $(DIST)/crashreporter-symbols                                   \
 	  $(MAKE_SYM_STORE_PATH) >                                        \
 	  $(DIST)/crashreporter-symbols/$(SYMBOL_INDEX_NAME)
 	echo packing symbols
--- a/accessible/src/base/NotificationController.h
+++ b/accessible/src/base/NotificationController.h
@@ -198,16 +198,21 @@ public:
                                    Arg* aArg)
   {
     nsRefPtr<Notification> notification =
       new TNotification<Class, Arg>(aInstance, aMethod, aArg);
     if (notification && mNotifications.AppendElement(notification))
       ScheduleProcessing();
   }
 
+#ifdef DEBUG
+  bool IsUpdating() const
+    { return mObservingState == eRefreshProcessingForUpdate; }
+#endif
+
 protected:
   nsAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
   /**
    * Start to observe refresh to make notifications and events processing after
    * layout.
    */
--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -89,16 +89,28 @@ nsAccDocManager::FindAccessibleInCache(n
   arg.mNode = aNode;
 
   mDocAccessibleCache.EnumerateRead(SearchAccessibleInDocCache,
                                     static_cast<void*>(&arg));
 
   return arg.mAccessible;
 }
 
+#ifdef DEBUG
+bool
+nsAccDocManager::IsProcessingRefreshDriverNotification() const
+{
+  bool isDocRefreshing = false;
+  mDocAccessibleCache.EnumerateRead(SearchIfDocIsRefreshing,
+                                    static_cast<void*>(&isDocRefreshing));
+
+  return isDocRefreshing;
+}
+#endif
+
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccDocManager protected
 
 bool
 nsAccDocManager::Init()
 {
   mDocAccessibleCache.Init(4);
@@ -462,8 +474,27 @@ nsAccDocManager::SearchAccessibleInDocCa
       static_cast<nsSearchAccessibleInCacheArg*>(aUserArg);
     arg->mAccessible = aDocAccessible->GetAccessible(arg->mNode);
     if (arg->mAccessible)
       return PL_DHASH_STOP;
   }
 
   return PL_DHASH_NEXT;
 }
+
+#ifdef DEBUG
+PLDHashOperator
+nsAccDocManager::SearchIfDocIsRefreshing(const nsIDocument* aKey,
+                                         nsDocAccessible* aDocAccessible,
+                                         void* aUserArg)
+{
+  NS_ASSERTION(aDocAccessible,
+               "No doc accessible for the object in doc accessible cache!");
+
+  if (aDocAccessible && aDocAccessible->mNotificationController &&
+      aDocAccessible->mNotificationController->IsUpdating()) {
+    *(static_cast<bool*>(aUserArg)) = true;
+    return PL_DHASH_STOP;
+  }
+
+  return PL_DHASH_NEXT;
+}
+#endif
--- a/accessible/src/base/nsAccDocManager.h
+++ b/accessible/src/base/nsAccDocManager.h
@@ -86,16 +86,20 @@ public:
   /**
    * Called by document accessible when it gets shutdown.
    */
   inline void NotifyOfDocumentShutdown(nsIDocument* aDocument)
   {
     mDocAccessibleCache.Remove(aDocument);
   }
 
+#ifdef DEBUG
+  bool IsProcessingRefreshDriverNotification() const;
+#endif
+
 protected:
   nsAccDocManager() { };
 
   /**
    * Initialize the manager.
    */
   bool Init();
 
@@ -152,16 +156,22 @@ private:
     nsINode* mNode;
   };
 
   static PLDHashOperator
     SearchAccessibleInDocCache(const nsIDocument* aKey,
                                nsDocAccessible* aDocAccessible,
                                void* aUserArg);
 
+#ifdef DEBUG
+  static PLDHashOperator
+    SearchIfDocIsRefreshing(const nsIDocument* aKey,
+                            nsDocAccessible* aDocAccessible, void* aUserArg);
+#endif
+
   nsDocAccessibleHashtable mDocAccessibleCache;
 };
 
 /**
  * nsAccDocManager debugging macros.
  */
 #ifdef DEBUG_ACCDOCMGR
 
--- a/accessible/tests/mochitest/events/test_tree.xul
+++ b/accessible/tests/mochitest/events/test_tree.xul
@@ -154,25 +154,30 @@
         gTreeBox.rowCountChanged(0, 1);
       }
 
       this.eventSeq =
       [
         new rowCountChangedChecker("insertRow: ", 0, 1),
         new treeInvalidatedChecker("insertRow", 0, 5, null, null)
       ];
+
+      this.getID = function insertRow_getID()
+      {
+        return "insert row";
+      }
     }
 
     /**
      * Invalidates first column and checks six name changed events for each
      * treeitem plus TreeInvalidated event.
      */
     function invalidateColumn()
     {
-      this.invoke = function()
+      this.invoke = function invalidateColumn_invoke()
       {
         // Make sure accessibles for the tree is created because it makes
         // sure accessible events will be fired.
         // Make sure tree children accessibles are created otherwise they won't
         // be a cause of name changed events.
         ensureAccessibleTree(gTree);
 
         // Fire 'TreeInvalidated' event by InvalidateColumn()
@@ -188,26 +193,31 @@
         new nameChangeChecker("invalidateColumn: ", 0, 0),
         new nameChangeChecker("invalidateColumn: ", 1, 0),
         new nameChangeChecker("invalidateColumn: ", 2, 0),
         new nameChangeChecker("invalidateColumn: ", 3, 0),
         new nameChangeChecker("invalidateColumn: ", 4, 0),
         new nameChangeChecker("invalidateColumn: ", 5, 0),
         new treeInvalidatedChecker("invalidateColumn", null, null, 0, 0)
       ];
+
+      this.getID = function invalidateColumn_getID()
+      {
+        return "invalidate column";
+      }
     }
 
     /**
      * Invalidates second row and checks name changed event for first treeitem
      * (note, there are two name changed events on linux due to different
      * accessible tree for xul:tree element) plus TreeInvalidated event.
      */
     function invalidateRow()
     {
-      this.invoke = function()
+      this.invoke = function invalidateRow_invoke()
       {
         // Fire 'TreeInvalidated' event by InvalidateRow()
         var colCount = gTree.columns.count;
         var column = gTree.columns.getFirstColumn();
         while (column) {
           gView.setCellText(1, column, "aloha 1x" + String(column.index));
           column = column.getNext();
         }
@@ -216,27 +226,33 @@
       }
 
       this.eventSeq =
       [
         new nameChangeChecker("invalidateColumn: ", 1, 0),
         new nameChangeChecker("invalidateColumn: ", 1, 1),
         new treeInvalidatedChecker("invalidateColumn", 1, 1, null, null)
       ];
+
+      this.getID = function invalidateRow_getID()
+      {
+        return "invalidate row";
+      }
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // Test
 
     var gTree = null;
     var gTreeBox = null;
     var gTreeView = null;
     var gQueue = null;
 
     // gA11yEventDumpID = "debug";
+    gA11yEventDumpToConsole = true; // debuggin
 
     function doTest()
     {
       // Initialize the tree
       gTree = document.getElementById("tree");
       gTreeBox = gTree.treeBoxObject;
       gView = new nsTableTreeView(5);
 
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -411,16 +411,17 @@ TARGET_OS	= @TARGET_OS@
 TARGET_MD_ARCH	= @TARGET_MD_ARCH@
 TARGET_XPCOM_ABI = @TARGET_XPCOM_ABI@
 
 AUTOCONF	= @AUTOCONF@
 GMAKE		= @GMAKE@
 PERL		= @PERL@
 PYTHON		= @PYTHON@
 RANLIB		= @RANLIB@
+OBJCOPY		= @OBJCOPY@
 UNZIP		= @UNZIP@
 ZIP		= @ZIP@
 XARGS		= @XARGS@
 STRIP		= @STRIP@
 DOXYGEN		= @DOXYGEN@
 PBBUILD_BIN	= @PBBUILD@
 SDP		= @SDP@
 NSINSTALL_BIN	= @NSINSTALL_BIN@
--- a/configure.in
+++ b/configure.in
@@ -366,16 +366,17 @@ case "$target" in
     AS="$android_toolchain"/bin/"$android_tool_prefix"-as
     CC="$android_toolchain"/bin/"$android_tool_prefix"-gcc
     CXX="$android_toolchain"/bin/"$android_tool_prefix"-g++
     CPP="$android_toolchain"/bin/"$android_tool_prefix"-cpp
     LD="$android_toolchain"/bin/"$android_tool_prefix"-ld
     AR="$android_toolchain"/bin/"$android_tool_prefix"-ar
     RANLIB="$android_toolchain"/bin/"$android_tool_prefix"-ranlib
     STRIP="$android_toolchain"/bin/"$android_tool_prefix"-strip
+    OBJCOPY="$android_toolchain"/bin/"$android_tool_prefix"-objcopy
 
     case "${target_cpu}" in
     arm*)
       ANDROID_CPU_ARCH=armeabi-v7a
       ;;
     i?86)
       ANDROID_CPU_ARCH=x86
       ;;
@@ -438,24 +439,28 @@ case "$target" in
 
     AC_DEFINE(ANDROID)
     AC_DEFINE_UNQUOTED(ANDROID_VERSION, $android_version)
     AC_SUBST(ANDROID_VERSION)
     CROSS_COMPILE=1
     MOZ_CHROME_FILE_FORMAT=omni
     ZLIB_DIR=yes
     ;;
+*-linux*)
+    AC_PATH_PROG(OBJCOPY,objcopy)
+    ;;
 esac
 
 AC_SUBST(ANDROID_NDK)
 AC_SUBST(ANDROID_TOOLCHAIN)
 AC_SUBST(ANDROID_PLATFORM)
 AC_SUBST(ANDROID_SDK)
 AC_SUBST(ANDROID_PLATFORM_TOOLS)
 AC_SUBST(ANDROID_PACKAGE_NAME)
+AC_SUBST(OBJCOPY)
 
 dnl ========================================================
 dnl Checks for compilers.
 dnl ========================================================
 dnl Set CROSS_COMPILE in the environment when running configure
 dnl to use the cross-compile setup for now
 dnl ========================================================
 
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -186,33 +186,33 @@ private:
   GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
 
     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
     WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name);
     if (!worker) {
-      return false;
+      return !JS_IsExceptionPending(aCx);
     }
 
     return worker->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
   }
 
   static JSBool
   SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
                    jsval* aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
 
     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
     WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name);
     if (!worker) {
-      return false;
+      return !JS_IsExceptionPending(aCx);
     }
 
     return worker->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
   }
 
   static JSBool
   Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
   {
@@ -243,31 +243,31 @@ private:
   static JSBool
   Terminate(JSContext* aCx, uintN aArgc, jsval* aVp)
   {
     JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
 
     const char*& name = sFunctions[0].name;
     WorkerPrivate* worker = GetInstancePrivate(aCx, obj, name);
     if (!worker) {
-      return false;
+      return !JS_IsExceptionPending(aCx);
     }
 
     return worker->Terminate(aCx);
   }
 
   static JSBool
   PostMessage(JSContext* aCx, uintN aArgc, jsval* aVp)
   {
     JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
 
     const char*& name = sFunctions[1].name;
     WorkerPrivate* worker = GetInstancePrivate(aCx, obj, name);
     if (!worker) {
-      return false;
+      return !JS_IsExceptionPending(aCx);
     }
 
     jsval message;
     if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &message)) {
       return false;
     }
 
     return worker->PostMessage(aCx, message);
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -110,17 +110,18 @@
             android:excludeFromRecents="true">
           <intent-filter>
             <action android:name="org.mozilla.gecko.reportCrash" />
           </intent-filter>
 	</activity>
 #endif
 
         <activity android:name="LauncherShortcuts"
-                  android:label="@string/launcher_shortcuts_title">
+                  android:label="@string/launcher_shortcuts_title"
+                  android:theme="@android:style/Theme.Translucent">
             <!--  This intent-filter allows your shortcuts to be created in the launcher. -->
             <intent-filter>
                 <action android:name="android.intent.action.CREATE_SHORTCUT" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
     </application>
 </manifest> 
--- a/embedding/android/LauncherShortcuts.java.in
+++ b/embedding/android/LauncherShortcuts.java.in
@@ -55,39 +55,39 @@ import android.util.*;
 import android.widget.*;
 import android.database.sqlite.*;
 import android.database.*;
 import android.view.*;
 import android.net.Uri;
 import android.graphics.*;
 
 
-public class LauncherShortcuts extends ListActivity {
+public class LauncherShortcuts extends Activity {
 
     private ArrayList <HashMap<String, String>> mWebappsList;
     private File mWebappsFolder;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
         setContentView(R.layout.launch_app_list);
 
         final Intent intent = getIntent();
         final String action = intent.getAction();
 
         if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
             // Doing it as a background task, as it involves file access
             new FetchWebApps().execute();
         }
     }
 
-    @Override
-    public void onListItemClick(ListView l, View v, int position, long id) {
-        HashMap<String, String> map = mWebappsList.get((int) id);
+    public void onListItemClick(int id) {
+        HashMap<String, String> map = mWebappsList.get(id);
         
         String uri = map.get("uri").toString();
         String title = map.get("title").toString();
         String appKey = map.get("appKey").toString();
         String favicon = map.get("favicon").toString();
         
         File manifestFile = new File(mWebappsFolder, appKey + "/manifest.json");
         
@@ -124,18 +124,21 @@ public class LauncherShortcuts extends L
                 break;
             case DisplayMetrics.DENSITY_HIGH:
                 size = 72;
                 break;
             default:
                 size = 72;
         }
 
-        Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(favicon), size, size, true);
-        intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
+        Bitmap bitmap = BitmapFactory.decodeFile(favicon);
+        if (bitmap != null) {
+            Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true);
+            intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, scaledBitmap);
+        }
 
         // Now, return the result to the launcher
         setResult(RESULT_OK, intent);
         finish();
     }
     
     private class FetchWebApps extends AsyncTask<Void, Void, Void> {
         
@@ -211,22 +214,48 @@ public class LauncherShortcuts extends L
             } catch (JSONException e) {}
             
             return null;
         }
         
         @Override
         protected void onPostExecute(Void unused) {
             if (mWebappsList != null) {
-                TextView emptyText = (TextView)findViewById(android.R.id.empty);
-                emptyText.setText("");
-
-                setListAdapter(new SimpleAdapter(
+                AlertDialog.Builder builder;
+                
+                if (android.os.Build.VERSION.SDK_INT >= 11) {
+                    builder = new AlertDialog.Builder(LauncherShortcuts.this, AlertDialog.THEME_HOLO_LIGHT);
+                } else {
+                    builder = new AlertDialog.Builder(LauncherShortcuts.this);
+                }
+                
+                builder.setTitle(R.string.launcher_shortcuts_title);
+                builder.setAdapter(new SimpleAdapter(
                     LauncherShortcuts.this,
                     mWebappsList,
                     R.layout.launch_app_listitem,
                     new String[] { "favicon", "title" },
                     new int[] { R.id.favicon, R.id.title }
-                ));
+                ), new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int id) {
+                        dialog.dismiss();
+                        onListItemClick(id);
+                        finish();
+                    }
+                });
+                
+                builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
+                    @Override
+                    public void onCancel(DialogInterface dialog) {
+                        dialog.dismiss();
+                        finish();
+                    }
+                });
+                
+                builder.create().show();
+            } else {
+                Toast.makeText(LauncherShortcuts.this, R.string.launcher_shortcuts_empty, Toast.LENGTH_LONG).show();
+                finish();
             }
         }
     }
 }
--- a/embedding/android/resources/layout/launch_app_list.xml
+++ b/embedding/android/resources/layout/launch_app_list.xml
@@ -1,20 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:padding="3dip"
          android:orientation="vertical"
          android:windowIsFloating="true">
-
-    <ListView android:id="@android:id/list"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layout_weight="1"
-              android:drawSelectorOnTop="false"/>
-
-    <TextView android:id="@android:id/empty"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:gravity="center"
-              android:text="@string/launcher_shortcuts_empty"/>
  </LinearLayout>
--- a/embedding/android/resources/layout/launch_app_listitem.xml
+++ b/embedding/android/resources/layout/launch_app_listitem.xml
@@ -1,17 +1,25 @@
 <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/listPreferredItemHeight"
-    android:padding="6dip"
-    android:orientation="horizontal">
+    android:paddingLeft="16dip"
+    android:paddingRight="16dip"
+    android:orientation="horizontal"
+    android:gravity="left">
     <ImageView
         android:id="@+id/favicon"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_marginRight="6dip"/>
+        android:layout_width="48dip"
+        android:layout_height="48dip"
+        android:layout_marginRight="12dip"
+        android:layout_gravity="center_vertical"
+        android:adjustViewBounds="true"
+        android:scaleType="fitCenter"/>
     <TextView
         android:id="@+id/title"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:gravity="center_vertical"/>
+        android:gravity="center_vertical"
+        android:textAppearance="?android:attr/textAppearanceLargeInverse"
+        android:ellipsize="marquee"
+        android:fadingEdge="horizontal"/>
  </LinearLayout>
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -75,19 +75,23 @@ class BumpChunk
 {
     char        *bump;
     char        *limit;
     BumpChunk   *next_;
     size_t      bumpSpaceSize;
 
     char *base() const { return limit - bumpSpaceSize; }
 
+    BumpChunk *thisDuringConstruction() { return this; }
+
     explicit BumpChunk(size_t bumpSpaceSize)
-      : bump(reinterpret_cast<char *>(this) + sizeof(BumpChunk)), limit(bump + bumpSpaceSize),
-        next_(NULL), bumpSpaceSize(bumpSpaceSize) {
+      : bump(reinterpret_cast<char *>(thisDuringConstruction()) + sizeof(BumpChunk)),
+        limit(bump + bumpSpaceSize),
+        next_(NULL), bumpSpaceSize(bumpSpaceSize)
+    {
         JS_ASSERT(bump == AlignPtr(bump));
     }
 
     void clobberUnused() {
 #ifdef DEBUG
         memset(bump, 0xcd, limit - bump);
 #endif
     }
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -519,18 +519,19 @@ struct Lifetime
 
     Lifetime(uint32 offset, uint32 savedEnd, Lifetime *next)
         : start(offset), end(offset), savedEnd(savedEnd),
           loopTail(false), write(false), next(next)
     {}
 };
 
 /* Basic information for a loop. */
-struct LoopAnalysis
+class LoopAnalysis
 {
+  public:
     /* Any loop this one is nested in. */
     LoopAnalysis *parent;
 
     /* Offset of the head of the loop. */
     uint32 head;
 
     /*
      * Offset of the unique jump going to the head of the loop. The code
@@ -842,31 +843,34 @@ SSAValue::phiValue(uint32 i) const
 
 inline types::TypeSet *
 SSAValue::phiTypes() const
 {
     JS_ASSERT(kind() == PHI);
     return &u.phi.node->types;
 }
 
-struct SSAUseChain
+class SSAUseChain
 {
+  public:
     bool popped : 1;
     uint32 offset : 31;
+    /* FIXME: Assert that only the proper arm of this union is accessed. */
     union {
         uint32 which;
         SSAPhiNode *phi;
     } u;
     SSAUseChain *next;
 
     SSAUseChain() { PodZero(this); }
 };
 
-struct SlotValue
+class SlotValue
 {
+  public:
     uint32 slot;
     SSAValue value;
     SlotValue(uint32 slot, const SSAValue &value) : slot(slot), value(value) {}
 };
 
 /* Analysis information about a script. */
 class ScriptAnalysis
 {
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -678,17 +678,16 @@ struct JSRuntime {
 
 #if defined(MOZ_GCTIMER) || defined(JSGC_TESTPILOT)
     struct GCData {
         GCData()
           : firstEnter(0),
             firstEnterValid(false)
 #ifdef JSGC_TESTPILOT
             , infoEnabled(false),
-            info(),
             start(0),
             count(0)
 #endif
         { }
 
         /*
          * Timestamp of the first GCTimer -- application runtime is determined
          * relative to this value.
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -9268,57 +9268,59 @@ FoldXMLConstants(JSContext *cx, JSParseN
             pn->setOp(JSOP_TOXML);
         }
     }
     return JS_TRUE;
 }
 
 #endif /* JS_HAS_XML_SUPPORT */
 
-static int
+enum Truthiness { Truthy, Falsy, Unknown };
+
+static Truthiness
 Boolish(JSParseNode *pn)
 {
     switch (pn->getOp()) {
       case JSOP_DOUBLE:
-        return pn->pn_dval != 0 && !JSDOUBLE_IS_NaN(pn->pn_dval);
+        return (pn->pn_dval != 0 && !JSDOUBLE_IS_NaN(pn->pn_dval)) ? Truthy : Falsy;
 
       case JSOP_STRING:
-        return pn->pn_atom->length() != 0;
+        return (pn->pn_atom->length() > 0) ? Truthy : Falsy;
 
 #if JS_HAS_GENERATOR_EXPRS
       case JSOP_CALL:
       {
         /*
          * A generator expression as an if or loop condition has no effects, it
          * simply results in a truthy object reference. This condition folding
          * is needed for the decompiler. See bug 442342 and bug 443074.
          */
         if (pn->pn_count != 1)
-            break;
+            return Unknown;
         JSParseNode *pn2 = pn->pn_head;
         if (!pn2->isKind(TOK_FUNCTION))
-            break;
+            return Unknown;
         if (!(pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA))
-            break;
-        /* FALL THROUGH */
+            return Unknown;
+        return Truthy;
       }
 #endif
 
       case JSOP_DEFFUN:
       case JSOP_LAMBDA:
       case JSOP_TRUE:
-        return 1;
+        return Truthy;
 
       case JSOP_NULL:
       case JSOP_FALSE:
-        return 0;
-
-      default:;
-    }
-    return -1;
+        return Falsy;
+
+      default:
+        return Unknown;
+    }
 }
 
 JSBool
 js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
 {
     JSParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
 
     JS_CHECK_RECURSION(cx, return JS_FALSE);
@@ -9498,60 +9500,62 @@ js_FoldConstants(JSContext *cx, JSParseN
 
       case TOK_OR:
       case TOK_AND:
         if (inCond) {
             if (pn->isArity(PN_LIST)) {
                 JSParseNode **pnp = &pn->pn_head;
                 JS_ASSERT(*pnp == pn1);
                 do {
-                    int cond = Boolish(pn1);
-                    if (cond == pn->isKind(TOK_OR)) {
+                    Truthiness t = Boolish(pn1);
+                    if (t == Unknown) {
+                        pnp = &pn1->pn_next;
+                        continue;
+                    }
+                    if ((t == Truthy) == pn->isKind(TOK_OR)) {
                         for (pn2 = pn1->pn_next; pn2; pn2 = pn3) {
                             pn3 = pn2->pn_next;
                             RecycleTree(pn2, tc);
                             --pn->pn_count;
                         }
                         pn1->pn_next = NULL;
                         break;
                     }
-                    if (cond != -1) {
-                        JS_ASSERT(cond == pn->isKind(TOK_AND));
-                        if (pn->pn_count == 1)
-                            break;
-                        *pnp = pn1->pn_next;
-                        RecycleTree(pn1, tc);
-                        --pn->pn_count;
-                    } else {
-                        pnp = &pn1->pn_next;
-                    }
+                    JS_ASSERT((t == Truthy) == pn->isKind(TOK_AND));
+                    if (pn->pn_count == 1)
+                        break;
+                    *pnp = pn1->pn_next;
+                    RecycleTree(pn1, tc);
+                    --pn->pn_count;
                 } while ((pn1 = *pnp) != NULL);
 
                 // We may have to change arity from LIST to BINARY.
                 pn1 = pn->pn_head;
                 if (pn->pn_count == 2) {
                     pn2 = pn1->pn_next;
                     pn1->pn_next = NULL;
                     JS_ASSERT(!pn2->pn_next);
                     pn->setArity(PN_BINARY);
                     pn->pn_left = pn1;
                     pn->pn_right = pn2;
                 } else if (pn->pn_count == 1) {
                     pn->become(pn1);
                     RecycleTree(pn1, tc);
                 }
             } else {
-                int cond = Boolish(pn1);
-                if (cond == pn->isKind(TOK_OR)) {
-                    RecycleTree(pn2, tc);
-                    pn->become(pn1);
-                } else if (cond != -1) {
-                    JS_ASSERT(cond == pn->isKind(TOK_AND));
-                    RecycleTree(pn1, tc);
-                    pn->become(pn2);
+                Truthiness t = Boolish(pn1);
+                if (t != Unknown) {
+                    if ((t == Truthy) == pn->isKind(TOK_OR)) {
+                        RecycleTree(pn2, tc);
+                        pn->become(pn1);
+                    } else {
+                        JS_ASSERT((t == Truthy) == pn->isKind(TOK_AND));
+                        RecycleTree(pn1, tc);
+                        pn->become(pn2);
+                    }
                 }
             }
         }
         break;
 
       case TOK_ASSIGN:
         /*
          * Compound operators such as *= should be subject to folding, in case
@@ -9766,25 +9770,25 @@ js_FoldConstants(JSContext *cx, JSParseN
         }
         break;
 #endif /* JS_HAS_XML_SUPPORT */
 
       default:;
     }
 
     if (inCond) {
-        int cond = Boolish(pn);
-        if (cond >= 0) {
+        Truthiness t = Boolish(pn);
+        if (t != Unknown) {
             /*
              * We can turn function nodes into constant nodes here, but mutating function
              * nodes is tricky --- in particular, mutating a function node that appears on
              * a method list corrupts the method list. However, methods are M's in
              * statements of the form 'this.foo = M;', which we never fold, so we're okay.
              */
             PrepareNodeForMutation(pn, tc);
             pn->setKind(TOK_PRIMARY);
-            pn->setOp(cond ? JSOP_TRUE : JSOP_FALSE);
+            pn->setOp(t == Truthy ? JSOP_TRUE : JSOP_FALSE);
             pn->setArity(PN_NULLARY);
         }
     }
 
     return JS_TRUE;
 }
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -584,33 +584,33 @@ class UnwantedForeground : public Foregr
  *   JS_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the
  *     parameters to each constructor of the guard object; it declares
  *     (ifdef DEBUG) an additional parameter.
  *   JS_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each
  *     constructor.  It uses the parameter declared by
  *     JS_GUARD_OBJECT_NOTIFIER_PARAM.
  */
 #ifdef DEBUG
-class JSGuardObjectNotifier
+class JS_FRIEND_API(JSGuardObjectNotifier)
 {
 private:
     bool* mStatementDone;
 public:
     JSGuardObjectNotifier() : mStatementDone(NULL) {}
 
     ~JSGuardObjectNotifier() {
         *mStatementDone = true;
     }
 
     void setStatementDone(bool *aStatementDone) {
         mStatementDone = aStatementDone;
     }
 };
 
-class JSGuardObjectNotificationReceiver
+class JS_FRIEND_API(JSGuardObjectNotificationReceiver)
 {
 private:
     bool mStatementDone;
 public:
     JSGuardObjectNotificationReceiver() : mStatementDone(false) {}
 
     ~JSGuardObjectNotificationReceiver() {
         /*
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -132,16 +132,17 @@ namespace js {
 // provides default types for WeakMap's MarkPolicy template parameter.
 template <class Key, class Value> class DefaultMarkPolicy;
 
 // Common base class for all WeakMap specializations. The collector uses this to call
 // their markIteratively and sweep methods.
 class WeakMapBase {
   public:
     WeakMapBase() : next(NULL) { }
+    virtual ~WeakMapBase() { }
 
     void trace(JSTracer *tracer) {
         if (IS_GC_MARKING_TRACER(tracer)) {
             // We don't do anything with a WeakMap at trace time. Rather, we wait until as
             // many keys as possible have been marked, and add ourselves to the list of
             // known-live WeakMaps to be scanned in the iterative marking phase, by
             // markAllIteratively.
             JS_ASSERT(!tracer->eagerlyTraceWeakMaps);
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -3901,16 +3901,26 @@ PresShell::FlushPendingNotifications(moz
     "Flush_InterruptibleLayout",
     "Flush_Layout",
     "Flush_Display"
   };
   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, type: %s)", MOZ_FUNCTION_NAME,
                            __LINE__, docURL__.get(), flushTypeNames[aType - 1]);
 #endif
 
+#ifdef ACCESSIBILITY
+#ifdef DEBUG
+  nsAccessibilityService* accService = GetAccService();
+  if (accService) {
+    NS_ASSERTION(!accService->IsProcessingRefreshDriverNotification(),
+                 "Flush during accessible tree update!");
+  }
+#endif
+#endif
+
   NS_ASSERTION(aType >= Flush_Frames, "Why did we get called?");
 
   bool isSafeToFlush = IsSafeToFlush();
 
   // If layout could possibly trigger scripts, then it's only safe to flush if
   // it's safe to run script.
   bool hasHadScriptObject;
   if (mDocument->GetScriptHandlingObject(hasHadScriptObject) ||
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2272,22 +2272,22 @@ nsFrame::IsSelectable(bool* aSelectable,
   else
   if (selectStyle == NS_STYLE_USER_SELECT_MOZ_ALL)
     selectStyle = NS_STYLE_USER_SELECT_ALL;
   else
   if (selectStyle == NS_STYLE_USER_SELECT_MOZ_NONE)
     selectStyle = NS_STYLE_USER_SELECT_NONE;
 
   // return stuff
-  if (aSelectable)
-    *aSelectable = (selectStyle != NS_STYLE_USER_SELECT_NONE);
   if (aSelectStyle)
     *aSelectStyle = selectStyle;
   if (mState & NS_FRAME_GENERATED_CONTENT)
     *aSelectable = PR_FALSE;
+  else
+    *aSelectable = (selectStyle != NS_STYLE_USER_SELECT_NONE);
   return NS_OK;
 }
 
 /**
   * Handles the Mouse Press Event for the frame
  */
 NS_IMETHODIMP
 nsFrame::HandlePress(nsPresContext* aPresContext, 
@@ -4069,17 +4069,18 @@ nsIFrame::GetOffsetToCrossDoc(const nsIF
                   "Must have frame for destination coordinate system!");
   NS_ASSERTION(PresContext()->GetRootPresContext() ==
                  aOther->PresContext()->GetRootPresContext(),
                "trying to get the offset between frames in different document "
                "hierarchies?");
   if (PresContext()->GetRootPresContext() !=
         aOther->PresContext()->GetRootPresContext()) {
     // crash right away, we are almost certainly going to crash anyway.
-    *(static_cast<PRInt32*>(nsnull)) = 3;
+    NS_RUNTIMEABORT("trying to get the offset between frames in different "
+                    "document hierarchies?");
   }
 
   const nsIFrame* root = nsnull;
   // offset will hold the final offset
   // docOffset holds the currently accumulated offset at the current APD, it
   // will be converted and added to offset when the current APD changes.
   nsPoint offset(0, 0), docOffset(0, 0);
   const nsIFrame* f = this;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/mirroring-03-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<title>Test for mirroring parentheses in Hebrew text</title>
+</head>
+<body>
+<p dir="rtl"><span style="unicode-bidi:bidi-override; direction:ltr;">&#x05d2;(&#x05d1;)&#x05d0;</span></p>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/mirroring-03.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<head>
+<title>Test for mirroring parentheses in Hebrew text</title>
+</head>
+<body>
+<p dir="rtl">&#x05d0;(&#x05d1;)&#x05d2;</p>
+</body>
+</html>
+
--- a/layout/reftests/bidi/reftest.list
+++ b/layout/reftests/bidi/reftest.list
@@ -16,16 +16,17 @@ fails-if(Android) == bidi-006-j.html bid
 == bidiSVG-05.svg bidiSVG-05-ref.svg
 random-if(layersGPUAccelerated) == visualmarquee.html marquee-ref.html
 random-if(layersGPUAccelerated) == logicalmarquee.html marquee-ref.html
 == visualmarquee.html logicalmarquee.html
 # test for glyph mirroring in right-to-left text
 == mirroring-01.html mirroring-01-ref.html
 # quote marks are not supposed to mirror, but Unicode 5.0 said they should, so some systems do it
 random-if(cocoaWidget) == mirroring-02.html mirroring-02-ref.html
+== mirroring-03.html mirroring-03-ref.html
 == mixedChartype-00.html mixedChartype-00-ref.html
 == mixedChartype-00-j.html mixedChartype-00-ref.html
 == mixedChartype-01.html mixedChartype-01-ref.html
 == mixedChartype-01-j.html mixedChartype-01-ref.html
 == mixedChartype-02.html mixedChartype-02-ref.html
 == mixedChartype-02-j.html mixedChartype-02-ref.html
 == mixedChartype-03.html mixedChartype-03-ref.html
 == mixedChartype-03-j.html mixedChartype-03-ref.html
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1641,17 +1641,17 @@ HTTP(..) == 635639-1.html 635639-1-ref.h
 HTTP(..) == 635639-2.html 635639-2-ref.html
 random == 637597-1.html 637597-1-ref.html # bug 637597 was never really fixed!
 == 637852-1.html 637852-1-ref.html
 == 637852-2.html 637852-2-ref.html
 == 637852-3.html 637852-3-ref.html
 == 641770-1.html 641770-1-ref.html
 == 641856-1.html 641856-1-ref.html
 == 645491-1.html 645491-1-ref.html
-== 652301-1a.html 652301-1-ref.html
+needs-focus == 652301-1a.html 652301-1-ref.html
 == 652301-1b.html 652301-1-ref.html
 == 645768-1.html 645768-1-ref.html
 fails-if(layersGPUAccelerated&&cocoaWidget) == 650228-1.html 650228-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
 == 653930-1.html 653930-1-ref.html
 HTTP(..) == 654057-1.html 654057-1-ref.html
 fails-if(layersGPUAccelerated&&cocoaWidget) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
 == 652775-1.html 652775-1-ref.html
 == 655549-1.html 655549-1-ref.html
--- a/layout/reftests/editor/reftest.list
+++ b/layout/reftests/editor/reftest.list
@@ -35,17 +35,17 @@ fails-if(Android) != spellcheck-textarea
 fails-if(Android) != spellcheck-textarea-attr-dynamic.html spellcheck-textarea-ref.html
 fails-if(Android) != spellcheck-textarea-attr-dynamic-inherit.html spellcheck-textarea-ref.html
 fails-if(Android) != spellcheck-textarea-property-dynamic.html spellcheck-textarea-ref.html
 fails-if(Android) != spellcheck-textarea-property-dynamic-inherit.html spellcheck-textarea-ref.html
 fails-if(Android) != spellcheck-textarea-attr-dynamic-override.html spellcheck-textarea-ref.html
 fails-if(Android) != spellcheck-textarea-attr-dynamic-override-inherit.html spellcheck-textarea-ref.html
 fails-if(Android) != spellcheck-textarea-property-dynamic-override.html spellcheck-textarea-ref.html
 fails-if(Android) != spellcheck-textarea-property-dynamic-override-inherit.html spellcheck-textarea-ref.html
-== caret_on_focus.html caret_on_focus-ref.html
+needs-focus == caret_on_focus.html caret_on_focus-ref.html
 needs-focus != caret_on_textarea_lastline.html caret_on_textarea_lastline-ref.html
 needs-focus == input-text-onfocus-reframe.html input-text-onfocus-reframe-ref.html
 needs-focus == input-text-notheme-onfocus-reframe.html input-text-notheme-onfocus-reframe-ref.html
 needs-focus == caret_after_reframe.html caret_after_reframe-ref.html
 == nobogusnode-1.html nobogusnode-ref.html
 == nobogusnode-2.html nobogusnode-ref.html
 == spellcheck-hyphen-valid.html spellcheck-hyphen-valid-ref.html
 fails-if(Android) != spellcheck-hyphen-invalid.html spellcheck-hyphen-invalid-ref.html
@@ -62,11 +62,11 @@ fails-if(Android) != spellcheck-hyphen-m
 == 642800.html 642800-ref.html
 == selection_visibility_after_reframe.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-2.html selection_visibility_after_reframe-ref.html
 != selection_visibility_after_reframe-3.html selection_visibility_after_reframe-ref.html
 == 672709.html 672709-ref.html
 == 338427-1.html 338427-1-ref.html
 skip-if(Android) == 674212-spellcheck.html 674212-spellcheck-ref.html
 skip-if(Android) == 338427-2.html 338427-2-ref.html
-skip-if(Android) == 338427-3.html 338427-3-ref.html
+skip-if(Android) needs-focus == 338427-3.html 338427-3-ref.html
 skip-if(Android) == 462758-grabbers-resizers.html 462758-grabbers-resizers-ref.html
 == dynamic-overflow-change.html dynamic-overflow-change-ref.html
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -136,17 +136,18 @@ struct RuleValue : RuleSelectorPair {
 // ------------------------------
 // Rule hash table
 //
 
 // Uses any of the sets of ops below.
 struct RuleHashTableEntry : public PLDHashEntryHdr {
   // If you add members that have heap allocated memory be sure to change the
   // logic in RuleHashTableSizeOfEnumerator.
-  nsTArray<RuleValue> mRules;
+  // Auto length 1, because we always have at least one entry in mRules.
+  nsAutoTArray<RuleValue, 1> mRules;
 };
 
 struct RuleHashTagTableEntry : public RuleHashTableEntry {
   // If you add members that have heap allocated memory be sure to change the
   // logic in RuleHash::SizeOf.
   nsCOMPtr<nsIAtom> mTag;
 };
 
@@ -224,16 +225,29 @@ RuleHash_InitEntry(PLDHashTable *table, 
 
 static void
 RuleHash_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
 {
   RuleHashTableEntry* entry = static_cast<RuleHashTableEntry*>(hdr);
   entry->~RuleHashTableEntry();
 }
 
+static void
+RuleHash_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
+                   PLDHashEntryHdr *to)
+{
+  NS_PRECONDITION(from != to, "This is not going to work!");
+  RuleHashTableEntry *oldEntry =
+    const_cast<RuleHashTableEntry*>(
+      static_cast<const RuleHashTableEntry*>(from));
+  RuleHashTableEntry *newEntry = new (to) RuleHashTableEntry();
+  newEntry->mRules.SwapElements(oldEntry->mRules);
+  oldEntry->~RuleHashTableEntry();
+}
+
 static bool
 RuleHash_TagTable_MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
                       const void *key)
 {
   nsIAtom *match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>
                                               (key));
   nsIAtom *entry_atom = static_cast<const RuleHashTagTableEntry*>(hdr)->mTag;
 
@@ -252,16 +266,30 @@ RuleHash_TagTable_InitEntry(PLDHashTable
 
 static void
 RuleHash_TagTable_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
 {
   RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>(hdr);
   entry->~RuleHashTagTableEntry();
 }
 
+static void
+RuleHash_TagTable_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
+                            PLDHashEntryHdr *to)
+{
+  NS_PRECONDITION(from != to, "This is not going to work!");
+  RuleHashTagTableEntry *oldEntry =
+    const_cast<RuleHashTagTableEntry*>(
+      static_cast<const RuleHashTagTableEntry*>(from));
+  RuleHashTagTableEntry *newEntry = new (to) RuleHashTagTableEntry();
+  newEntry->mTag.swap(oldEntry->mTag);
+  newEntry->mRules.SwapElements(oldEntry->mRules);
+  oldEntry->~RuleHashTagTableEntry();
+}
+
 static nsIAtom*
 RuleHash_ClassTable_GetKey(PLDHashTable *table, const PLDHashEntryHdr *hdr)
 {
   const RuleHashTableEntry *entry =
     static_cast<const RuleHashTableEntry*>(hdr);
   return entry->mRules[0].mSelector->mClassList->mAtom;
 }
 
@@ -291,88 +319,88 @@ RuleHash_NameSpaceTable_MatchEntry(PLDHa
          entry->mRules[0].mSelector->mNameSpace;
 }
 
 static const PLDHashTableOps RuleHash_TagTable_Ops = {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   PL_DHashVoidPtrKeyStub,
   RuleHash_TagTable_MatchEntry,
-  PL_DHashMoveEntryStub,
+  RuleHash_TagTable_MoveEntry,
   RuleHash_TagTable_ClearEntry,
   PL_DHashFinalizeStub,
   RuleHash_TagTable_InitEntry
 };
 
 // Case-sensitive ops.
 static const RuleHashTableOps RuleHash_ClassTable_CSOps = {
   {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   PL_DHashVoidPtrKeyStub,
   RuleHash_CSMatchEntry,
-  PL_DHashMoveEntryStub,
+  RuleHash_MoveEntry,
   RuleHash_ClearEntry,
   PL_DHashFinalizeStub,
   RuleHash_InitEntry
   },
   RuleHash_ClassTable_GetKey
 };
 
 // Case-insensitive ops.
 static const RuleHashTableOps RuleHash_ClassTable_CIOps = {
   {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   RuleHash_CIHashKey,
   RuleHash_CIMatchEntry,
-  PL_DHashMoveEntryStub,
+  RuleHash_MoveEntry,
   RuleHash_ClearEntry,
   PL_DHashFinalizeStub,
   RuleHash_InitEntry
   },
   RuleHash_ClassTable_GetKey
 };
 
 // Case-sensitive ops.
 static const RuleHashTableOps RuleHash_IdTable_CSOps = {
   {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   PL_DHashVoidPtrKeyStub,
   RuleHash_CSMatchEntry,
-  PL_DHashMoveEntryStub,
+  RuleHash_MoveEntry,
   RuleHash_ClearEntry,
   PL_DHashFinalizeStub,
   RuleHash_InitEntry
   },
   RuleHash_IdTable_GetKey
 };
 
 // Case-insensitive ops.
 static const RuleHashTableOps RuleHash_IdTable_CIOps = {
   {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   RuleHash_CIHashKey,
   RuleHash_CIMatchEntry,
-  PL_DHashMoveEntryStub,
+  RuleHash_MoveEntry,
   RuleHash_ClearEntry,
   PL_DHashFinalizeStub,
   RuleHash_InitEntry
   },
   RuleHash_IdTable_GetKey
 };
 
 static const PLDHashTableOps RuleHash_NameSpaceTable_Ops = {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   RuleHash_NameSpaceTable_HashKey,
   RuleHash_NameSpaceTable_MatchEntry,
-  PL_DHashMoveEntryStub,
+  RuleHash_MoveEntry,
   RuleHash_ClearEntry,
   PL_DHashFinalizeStub,
   RuleHash_InitEntry
 };
 
 #undef RULE_HASH_STATS
 #undef PRINT_UNIVERSAL_RULES
 
@@ -745,17 +773,19 @@ RuleHash::SizeOf() const
   return n;
 }
 
 //--------------------------------
 
 // A hash table mapping atoms to lists of selectors
 struct AtomSelectorEntry : public PLDHashEntryHdr {
   nsIAtom *mAtom;
-  nsTArray<nsCSSSelector*> mSelectors;
+  // Auto length 2, because a decent fraction of these arrays ends up
+  // with 2 elements, and each entry is cheap.
+  nsAutoTArray<nsCSSSelector*, 2> mSelectors;
 };
 
 static void
 AtomSelector_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
 {
   (static_cast<AtomSelectorEntry*>(hdr))->~AtomSelectorEntry();
 }
 
@@ -764,43 +794,56 @@ AtomSelector_InitEntry(PLDHashTable *tab
                        const void *key)
 {
   AtomSelectorEntry *entry = static_cast<AtomSelectorEntry*>(hdr);
   new (entry) AtomSelectorEntry();
   entry->mAtom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
   return PR_TRUE;
 }
 
+static void
+AtomSelector_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
+                       PLDHashEntryHdr *to)
+{
+  NS_PRECONDITION(from != to, "This is not going to work!");
+  AtomSelectorEntry *oldEntry =
+    const_cast<AtomSelectorEntry*>(static_cast<const AtomSelectorEntry*>(from));
+  AtomSelectorEntry *newEntry = new (to) AtomSelectorEntry();
+  newEntry->mAtom = oldEntry->mAtom;
+  newEntry->mSelectors.SwapElements(oldEntry->mSelectors);
+  oldEntry->~AtomSelectorEntry();
+}
+
 static nsIAtom*
 AtomSelector_GetKey(PLDHashTable *table, const PLDHashEntryHdr *hdr)
 {
   const AtomSelectorEntry *entry = static_cast<const AtomSelectorEntry*>(hdr);
   return entry->mAtom;
 }
 
 // Case-sensitive ops.
 static const PLDHashTableOps AtomSelector_CSOps = {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   PL_DHashVoidPtrKeyStub,
   PL_DHashMatchEntryStub,
-  PL_DHashMoveEntryStub,
+  AtomSelector_MoveEntry,
   AtomSelector_ClearEntry,
   PL_DHashFinalizeStub,
   AtomSelector_InitEntry
 };
 
 // Case-insensitive ops.
 static const RuleHashTableOps AtomSelector_CIOps = {
   {
   PL_DHashAllocTable,
   PL_DHashFreeTable,
   RuleHash_CIHashKey,
   RuleHash_CIMatchEntry,
-  PL_DHashMoveEntryStub,
+  AtomSelector_MoveEntry,
   AtomSelector_ClearEntry,
   PL_DHashFinalizeStub,
   AtomSelector_InitEntry
   },
   AtomSelector_GetKey
 };
 
 //--------------------------------
--- a/mfbt/Util.h
+++ b/mfbt/Util.h
@@ -59,16 +59,22 @@
 MOZ_BEGIN_EXTERN_C
 
 extern MFBT_API(void)
 JS_Assert(const char *s, const char *file, JSIntn ln);
 
 MOZ_END_EXTERN_C
 
 /*
+ * A static assertion, just like PR_STATIC_ASSERT.
+ */
+#define MOZ_STATIC_ASSERT(condition) \
+  extern void moz_static_assert(int arg[(condition) ? 1 : -1])
+
+/*
  * MOZ_ASSERT() is a "strong" assertion of state, like libc's
  * assert().  If a MOZ_ASSERT() fails in a debug build, the process in
  * which it fails will stop running in a loud and dramatic way.
  */
 #ifdef DEBUG
 
 # define MOZ_ASSERT(expr_)                                      \
     ((expr_) ? (void)0 : JS_Assert(#expr_, __FILE__, __LINE__))
@@ -191,16 +197,103 @@ struct DebugOnly
     /*
      * DebugOnly must always have a destructor or else it will
      * generate "unused variable" warnings, exactly what it's intended
      * to avoid!
      */
     ~DebugOnly() {}
 };
 
+/*
+ * This class, and the corresponding macro MOZ_ALIGNOF, figure out how many 
+ * bytes of alignment a given type needs.
+ */
+template<class T>
+struct AlignmentFinder
+{
+private:
+  struct Aligner
+  {
+    char c;
+    T t;
+  };
+
+public:
+  static const int alignment = sizeof(Aligner) - sizeof(T);
+};
+
+#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
+
+/*
+ * Declare the MOZ_ALIGNED_DECL macro for declaring aligned types.
+ *
+ * For instance,
+ *
+ *   MOZ_ALIGNED_DECL(char arr[2], 8);
+ *
+ * will declare a two-character array |arr| aligned to 8 bytes.
+ */
+
+#if defined(__GNUC__)
+#define MOZ_ALIGNED_DECL(_type, _align) \
+  _type __attribute__((aligned(_align)))
+
+#elif defined(_MSC_VER)
+#define MOZ_ALIGNED_DECL(_type, _align) \
+  __declspec(align(_align)) _type
+
+#else
+
+#warning "We don't know how to align variables on this compiler."
+#define MOZ_ALIGNED_DECL(_type, _align) _type
+
+#endif
+
+/*
+ * AlignedElem<N> is a structure whose alignment is guaranteed to be at least N bytes.
+ *
+ * We support 1, 2, 4, 8, and 16-bit alignment.
+ */
+template<size_t align>
+struct AlignedElem;
+
+/*
+ * We have to specialize this template because GCC doesn't like __attribute__((aligned(foo))) where
+ * foo is a template parameter.
+ */
+
+template<>
+struct AlignedElem<1>
+{
+  MOZ_ALIGNED_DECL(uint8 elem, 1);
+};
+
+template<>
+struct AlignedElem<2>
+{
+  MOZ_ALIGNED_DECL(uint8 elem, 2);
+};
+
+template<>
+struct AlignedElem<4>
+{
+  MOZ_ALIGNED_DECL(uint8 elem, 4);
+};
+
+template<>
+struct AlignedElem<8>
+{
+  MOZ_ALIGNED_DECL(uint8 elem, 8);
+};
+
+template<>
+struct AlignedElem<16>
+{
+  MOZ_ALIGNED_DECL(uint8 elem, 16);
+};
 
 /*
  * This utility pales in comparison to Boost's aligned_storage. The utility
  * simply assumes that uint64 is enough alignment for anyone. This may need
  * to be extended one day...
  *
  * As an important side effect, pulling the storage into this template is
  * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving
--- a/mobile/chrome/content/input.js
+++ b/mobile/chrome/content/input.js
@@ -854,100 +854,97 @@ function KineticController(aPanBy, aEndC
 KineticController.prototype = {
   _reset: function _reset() {
     this._active = false;
     this._paused = false;
     this.momentumBuffer = [];
     this._velocity.set(0, 0);
   },
 
-  isActive: function isActive() {
-    return this._active;
+  _startTimer: function _startTimer() {
+    this._active = true;
+    mozRequestAnimationFrame(this);
   },
 
-  _startTimer: function _startTimer() {
-    let self = this;
+  _calcP: function _calcP(v0, a, t) {
+    // Important traits for this function:
+    //   p(t=0) is 0
+    //   p'(t=0) is v0
+    //
+    // We use exponential to get a smoother stop, but by itself exponential
+    // is too smooth at the end. Adding a polynomial with the appropriate
+    // weight helps to balance
+    let c = this._exponentialC;
+    return v0 * Math.exp(-t / c) * -c + a * t * t + v0 * c;
+  },
 
+  _calcV: function _calcV(v0, a, t) {
+    let c = this._exponentialC;
+    return v0 * Math.exp(-t / c) + 2 * a * t;
+  },
+
+  onBeforePaint: function onBeforePaint(timeStamp) {
     let lastp = this._position;  // track last position vector because pan takes deltas
     let v0 = this._velocity;  // initial velocity
     let a = this._acceleration;  // acceleration
-    let c = this._exponentialC;
-    let p = new Point(0, 0);
+    let px = 0;
+    let py = 0;
     let dx, dy, t, realt;
 
-    function calcP(v0, a, t) {
-      // Important traits for this function:
-      //   p(t=0) is 0
-      //   p'(t=0) is v0
-      //
-      // We use exponential to get a smoother stop, but by itself exponential
-      // is too smooth at the end. Adding a polynomial with the appropriate
-      // weight helps to balance
-      return v0 * Math.exp(-t / c) * -c + a * t * t + v0 * c;
+    // Someone called end() on us between timer intervals
+    // or we are paused.
+    if (!this.isActive() || this._paused)
+      return;
+
+    // To make animation end fast enough but to keep smoothness, average the ideal
+    // time frame (smooth animation) with the actual time lapse (end fast enough).
+    // Animation will never take longer than 2 times the ideal length of time.
+    realt = timeStamp - this._initialTime;
+    this._time += this._updateInterval;
+    t = (this._time + realt) / 2;
+
+    // Calculate new position.
+    px = this._calcP(v0.x, a.x, t);
+    py = this._calcP(v0.y, a.y, t);
+    dx = Math.round(px - lastp.x);
+    dy = Math.round(py - lastp.y);
+
+    // Test to see if movement is finished for each component.
+    if (dx * a.x > 0) {
+      dx = 0;
+      lastp.x = 0;
+      v0.x = 0;
+      a.x = 0;
     }
-
-    this._calcV = function(v0, a, t) {
-      return v0 * Math.exp(-t / c) + 2 * a * t;
+    // Symmetric to above case.
+    if (dy * a.y > 0) {
+      dy = 0;
+      lastp.y = 0;
+      v0.y = 0;
+      a.y = 0;
     }
 
-    let callback = {
-      onBeforePaint: function kineticHandleEvent(timeStamp) {
-        // Someone called end() on us between timer intervals
-        // or we are paused.
-        if (!self.isActive() || self._paused)
-          return;
-
-        // To make animation end fast enough but to keep smoothness, average the ideal
-        // time frame (smooth animation) with the actual time lapse (end fast enough).
-        // Animation will never take longer than 2 times the ideal length of time.
-        realt = timeStamp - self._initialTime;
-        self._time += self._updateInterval;
-        t = (self._time + realt) / 2;
-
-        // Calculate new position.
-        p.x = calcP(v0.x, a.x, t);
-        p.y = calcP(v0.y, a.y, t);
-        dx = Math.round(p.x - lastp.x);
-        dy = Math.round(p.y - lastp.y);
+    if (v0.x == 0 && v0.y == 0) {
+      this.end();
+    } else {
+      let panStop = false;
+      if (dx != 0 || dy != 0) {
+        try { panStop = !this._panBy(-dx, -dy, true); } catch (e) {}
+        lastp.add(dx, dy);
+      }
 
-        // Test to see if movement is finished for each component.
-        if (dx * a.x > 0) {
-          dx = 0;
-          lastp.x = 0;
-          v0.x = 0;
-          a.x = 0;
-        }
-        // Symmetric to above case.
-        if (dy * a.y > 0) {
-          dy = 0;
-          lastp.y = 0;
-          v0.y = 0;
-          a.y = 0;
-        }
+      if (panStop)
+        this.end();
+      else
+        mozRequestAnimationFrame(this);
+    }
+  },
 
-        if (v0.x == 0 && v0.y == 0) {
-          self.end();
-        } else {
-          let panStop = false;
-          if (dx != 0 || dy != 0) {
-            try { panStop = !self._panBy(-dx, -dy, true); } catch (e) {}
-            lastp.add(dx, dy);
-          }
-
-          if (panStop)
-            self.end();
-          else
-            mozRequestAnimationFrame(this);
-        }
-      }
-    };
-
-    this._active = true;
-    this._paused = false;
-    mozRequestAnimationFrame(callback);
+  isActive: function isActive() {
+    return this._active;
   },
 
   start: function start() {
     function sign(x) {
       return x ? ((x > 0) ? 1 : -1) : 0;
     }
 
     function clampFromZero(x, closerToZero, furtherFromZero) {
@@ -973,17 +970,16 @@ KineticController.prototype = {
         distanceY += me.dy;
       }
     }
 
     let currentVelocityX = 0;
     let currentVelocityY = 0;
 
     if (this.isActive()) {
-      // If active, then we expect this._calcV to be defined.
       let currentTime = Date.now() - this._initialTime;
       currentVelocityX = Util.clamp(this._calcV(this._velocity.x, this._acceleration.x, currentTime), -kMaxVelocity, kMaxVelocity);
       currentVelocityY = Util.clamp(this._calcV(this._velocity.y, this._acceleration.y, currentTime), -kMaxVelocity, kMaxVelocity);
     }
 
     if (currentVelocityX * this._velocity.x <= 0)
       currentVelocityX = 0;
     if (currentVelocityY * this._velocity.y <= 0)
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -200,19 +200,23 @@ pref("gfx.downloadable_fonts.enabled", t
 pref("gfx.downloadable_fonts.fallback_delay", 3000);
 pref("gfx.downloadable_fonts.sanitize", true);
 
 // see gfx/thebes/gfxUnicodeProperties.h for definitions of script bits
 #ifdef XP_MACOSX
 // use harfbuzz for default (0x01) + arabic (0x02) + hebrew (0x04) + thai (0x40)
 pref("gfx.font_rendering.harfbuzz.scripts", 71);
 #else
+#ifdef ANDROID
+pref("gfx.font_rendering.harfbuzz.scripts", 71);
+#else
 // use harfbuzz for default (0x01) + arabic (0x02)
 pref("gfx.font_rendering.harfbuzz.scripts", 3);
 #endif
+#endif
 
 #ifdef XP_WIN
 pref("gfx.font_rendering.directwrite.enabled", false);
 pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true);
 #endif
 
 #ifdef XP_WIN
 pref("gfx.canvas.azure.enabled", true);
--- a/netwerk/cache/nsMemoryCacheDevice.cpp
+++ b/netwerk/cache/nsMemoryCacheDevice.cpp
@@ -44,17 +44,17 @@
 #include "nsCacheService.h"
 #include "nsICacheService.h"
 #include "nsIStorageStream.h"
 #include "nsICacheVisitor.h"
 #include "nsCRT.h"
 #include "nsCache.h"
 #include "nsReadableUtils.h"
 
-// The memory cache implements a variation of the "LRU-SP" caching algorithm
+// The memory cache implements the "LRU-SP" caching algorithm
 // described in "LRU-SP: A Size-Adjusted and Popularity-Aware LRU Replacement
 // Algorithm for Web Caching" by Kai Cheng and Yahiko Kambayashi.
 
 // We keep kQueueCount LRU queues, which should be about ceil(log2(mHardLimit))
 // The queues hold exponentially increasing ranges of floor(log2((size/nref)))
 // values for entries.
 // Entries larger than 2^(kQueueCount-1) go in the last queue.
 // Entries with no expiration go in the first queue.
@@ -374,41 +374,59 @@ nsMemoryCacheDevice::EvictEntry(nsCacheE
     
     if (deleteEntry)  delete entry;
 }
 
 
 void
 nsMemoryCacheDevice::EvictEntriesIfNecessary(void)
 {
-    nsCacheEntry * entry, * next;
-
+    nsCacheEntry * entry;
+    nsCacheEntry * maxEntry;
     CACHE_LOG_DEBUG(("EvictEntriesIfNecessary.  mTotalSize: %d, mHardLimit: %d,"
                      "mInactiveSize: %d, mSoftLimit: %d\n",
                      mTotalSize, mHardLimit, mInactiveSize, mSoftLimit));
     
     if ((mTotalSize < mHardLimit) && (mInactiveSize < mSoftLimit))
         return;
 
-    for (int i = kQueueCount - 1; i >= 0; --i) {
-        entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList[i]);
-        while (entry != &mEvictionList[i]) {
-            if (entry->IsInUse()) {
+    PRUint32 now = SecondsFromPRTime(PR_Now());
+    PRUint64 entryCost = 0;
+    PRUint64 maxCost = 0;
+    do {
+        // LRU-SP eviction selection: Check the head of each segment (each
+        // eviction list, kept in LRU order) and select the maximal-cost
+        // entry for eviction. Cost is time-since-accessed * size / nref.
+        maxEntry = 0;
+        for (int i = kQueueCount - 1; i >= 0; --i) {
+            entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList[i]);
+
+            // If the head of a list is in use, check the next available entry
+            while ((entry != &mEvictionList[i]) &&
+                   (entry->IsInUse())) {
                 entry = (nsCacheEntry *)PR_NEXT_LINK(entry);
-                continue;
             }
 
-            next = (nsCacheEntry *)PR_NEXT_LINK(entry);
-            EvictEntry(entry, DELETE_ENTRY);
-            entry = next;
-
-            if ((mTotalSize < mHardLimit) && (mInactiveSize < mSoftLimit))
-                return;
+            if (entry != &mEvictionList[i]) {
+                entryCost = (PRUint64)
+                    (now - entry->LastFetched()) * entry->Size() / 
+                    PR_MAX(1, entry->FetchCount());
+                if (!maxEntry || (entryCost > maxCost)) {
+                    maxEntry = entry;
+                    maxCost = entryCost;
+                }
+            }
+        }
+        if (maxEntry) {
+            EvictEntry(maxEntry, DELETE_ENTRY);
+        } else {
+            break;
         }
     }
+    while ((mTotalSize >= mHardLimit) || (mInactiveSize >= mSoftLimit));
 }
 
 
 int
 nsMemoryCacheDevice::EvictionList(nsCacheEntry * entry, PRInt32  deltaSize)
 {
     // favor items which never expire by putting them in the lowest-index queue
     if (entry->ExpirationTime() == nsICache::NO_EXPIRATION_TIME)
--- a/toolkit/crashreporter/tools/symbolstore.py
+++ b/toolkit/crashreporter/tools/symbolstore.py
@@ -629,32 +629,33 @@ class Dumper_Win32(Dumper):
             call([pdbstr, "-w", "-p:" + os.path.basename(debug_file),
                   "-i:" + os.path.basename(streamFilename), "-s:srcsrv"],
                  cwd=os.path.dirname(stream_output_path))
             # clean up all the .stream files when done
             os.remove(stream_output_path)
         return result
 
 class Dumper_Linux(Dumper):
+    objcopy = os.environ['OBJCOPY'] if 'OBJCOPY' in os.environ else 'objcopy'
     def ShouldProcess(self, file):
         """This function will allow processing of files that are
         executable, or end with the .so extension, and additionally
         file(1) reports as being ELF files.  It expects to find the file
         command in PATH."""
         if file.endswith(".so") or os.access(file, os.X_OK):
             return self.RunFileCommand(file).startswith("ELF")
         return False
 
     def CopyDebug(self, file, debug_file, guid):
         # We want to strip out the debug info, and add a
         # .gnu_debuglink section to the object, so the debugger can
         # actually load our debug info later.
         file_dbg = file + ".dbg"
-        if call(['objcopy', '--only-keep-debug', file, file_dbg]) == 0 and \
-           call(['objcopy', '--add-gnu-debuglink=%s' % file_dbg, file]) == 0:
+        if call([self.objcopy, '--only-keep-debug', file, file_dbg]) == 0 and \
+           call([self.objcopy, '--add-gnu-debuglink=%s' % file_dbg, file]) == 0:
             rel_path = os.path.join(debug_file,
                                     guid,
                                     debug_file + ".dbg")
             full_path = os.path.normpath(os.path.join(self.symbol_path,
                                                       rel_path))
             shutil.move(file_dbg, full_path)
             # gzip the shipped debug files
             os.system("gzip %s" % full_path)
--- a/toolkit/mozapps/webapps/OpenWebapps.jsm
+++ b/toolkit/mozapps/webapps/OpenWebapps.jsm
@@ -136,19 +136,20 @@ let OpenWebapps = {
       storeURI: aApplication.storeURI,
       appURI: aApplication.appURI,
       installData: aApplication.installData,
       installTime: (new Date()).getTime()
     };
     this._writeFile(this.appsFile, JSON.stringify(this.webapps));
 
     // now save the icon as icon.png in the app directory
+    let iconURI = aApplication.iconURI ? aApplication.iconURI : "chrome://browser/skin/images/homescreen-default-hdpi.png";
     let iconFile = dir.clone();
     iconFile.append("icon.png");
-    let uri = Services.io.newURI(aApplication.iconURI, null, null);
+    let uri = Services.io.newURI(iconURI, null, null);
     let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
     persist.persistFlags = persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | persist.PERSIST_FLAGS_BYPASS_CACHE;
     persist.saveURI(uri, null, null, null, "", iconFile);
   },
  
   _appId: function(aURI) {
     for (let id in this.webapps) {
       if (this.webapps[id].appURI == aURI)
--- a/widget/public/nsWidgetInitData.h
+++ b/widget/public/nsWidgetInitData.h
@@ -127,17 +127,18 @@ struct nsWidgetInitData {
       mPopupHint(ePopupTypePanel),
       mPopupLevel(ePopupLevelTop),
       clipChildren(PR_FALSE), 
       clipSiblings(PR_FALSE), 
       mDropShadow(PR_FALSE),
       mListenForResizes(PR_FALSE),
       mUnicode(PR_TRUE),
       mRTL(PR_FALSE),
-      mNoAutoHide(PR_FALSE)
+      mNoAutoHide(PR_FALSE),
+      mIsDragPopup(PR_FALSE)
   {
   }
 
   nsWindowType  mWindowType;
   nsBorderStyle mBorderStyle;
   nsPopupType   mPopupHint;
   nsPopupLevel  mPopupLevel;
   // when painting exclude area occupied by child windows and sibling windows
--- a/widget/src/android/nsToolkit.cpp
+++ b/widget/src/android/nsToolkit.cpp
@@ -42,20 +42,22 @@
 
 NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit)
 
 // why do we have this?
 static PRUintn gToolkitTLSIndex = 0;
 
 nsToolkit::nsToolkit()
 {
+    MOZ_COUNT_CTOR(nsToolkit);
 }
 
 nsToolkit::~nsToolkit()
 {
+    MOZ_COUNT_DTOR(nsToolkit);
     PR_SetThreadPrivate(gToolkitTLSIndex, nsnull);
 }
 
 NS_IMETHODIMP
 nsToolkit::Init(PRThread *aThread)
 {
     nsWidgetAtoms::RegisterAtoms();
     return NS_OK;
--- a/widget/src/cocoa/nsToolkit.mm
+++ b/widget/src/cocoa/nsToolkit.mm
@@ -85,20 +85,22 @@ static io_connect_t gRootPort = MACH_POR
 static PRUintn gToolkitTLSIndex = 0;
 
 nsToolkit::nsToolkit()
 : mInited(false)
 , mSleepWakeNotificationRLS(nsnull)
 , mEventTapPort(nsnull)
 , mEventTapRLS(nsnull)
 {
+  MOZ_COUNT_CTOR(nsToolkit);
 }
 
 nsToolkit::~nsToolkit()
 {
+  MOZ_COUNT_DTOR(nsToolkit);
   RemoveSleepWakeNotifcations();
   UnregisterAllProcessMouseEventHandlers();
   // Remove the TLS reference to the toolkit...
   PR_SetThreadPrivate(gToolkitTLSIndex, nsnull);
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsToolkit, nsIToolkit);
 
--- a/widget/src/gtk2/nsClipboard.cpp
+++ b/widget/src/gtk2/nsClipboard.cpp
@@ -948,69 +948,59 @@ wait_for_retrieval(GtkClipboard *clipboa
 
 static void
 clipboard_contents_received(GtkClipboard     *clipboard,
                             GtkSelectionData *selection_data,
                             gpointer          data)
 {
     retrieval_context *context = static_cast<retrieval_context *>(data);
     if (context->timed_out) {
-        delete context;
         return;
     }
 
     context->completed = true;
 
     if (selection_data->length >= 0)
         context->data = gtk_selection_data_copy(selection_data);
 }
 
 
 static GtkSelectionData *
 wait_for_contents(GtkClipboard *clipboard, GdkAtom target)
 {
-    retrieval_context *context = new retrieval_context();
+    retrieval_context context;
     gtk_clipboard_request_contents(clipboard, target,
                                    clipboard_contents_received,
-                                   context);
+                                   &context);
 
-    if (!wait_for_retrieval(clipboard, context)) {
-        // Don't delete |context|; the callback will when it eventually
-        // comes back.
+    if (!wait_for_retrieval(clipboard, &context)) {
         return nsnull;
     }
 
-    GtkSelectionData *result = static_cast<GtkSelectionData *>(context->data);
-    delete context;
-    return result;
+    return static_cast<GtkSelectionData *>(context.data);
 }
 
 static void
 clipboard_text_received(GtkClipboard *clipboard,
                         const gchar  *text,
                         gpointer      data)
 {
     retrieval_context *context = static_cast<retrieval_context *>(data);
     if (context->timed_out) {
-        delete context;
         return;
     }
 
     context->completed = true;
     context->data = g_strdup(text);
 }
 
 static gchar *
 wait_for_text(GtkClipboard *clipboard)
 {
-    retrieval_context *context = new retrieval_context();
-    gtk_clipboard_request_text(clipboard, clipboard_text_received, context);
+    retrieval_context context;
+    gtk_clipboard_request_text(clipboard, clipboard_text_received, &context);
 
-    if (!wait_for_retrieval(clipboard, context)) {
-        // Don't delete |context|; the callback will when it eventually
-        // comes back.
+    if (!wait_for_retrieval(clipboard, &context)) {
         return nsnull;
     }
 
-    gchar *result = static_cast<gchar *>(context->data);
-    delete context;
-    return result;
+    return static_cast<gchar *>(context.data);
 }
--- a/widget/src/os2/nsToolkit.cpp
+++ b/widget/src/os2/nsToolkit.cpp
@@ -50,26 +50,28 @@ static PRUintn gToolkitTLSIndex = 0;
 
 //-------------------------------------------------------------------------
 //
 // constructor
 //
 //-------------------------------------------------------------------------
 nsToolkit::nsToolkit()  
 {
+    MOZ_COUNT_CTOR(nsToolkit);
 }
 
 
 //-------------------------------------------------------------------------
 //
 // destructor
 //
 //-------------------------------------------------------------------------
 nsToolkit::~nsToolkit()
 {
+    MOZ_COUNT_DTOR(nsToolkit);
     // Remove the TLS reference to the toolkit...
     PR_SetThreadPrivate(gToolkitTLSIndex, nsnull);
 }
 
 //-------------------------------------------------------------------------
 //
 //
 //-------------------------------------------------------------------------
--- a/widget/src/qt/nsToolkit.cpp
+++ b/widget/src/qt/nsToolkit.cpp
@@ -50,23 +50,25 @@
 // object associated with a given thread...
 static PRUintn gToolkitTLSIndex = 0;
 
 //-------------------------------------------------------------------------
 // constructor
 //-------------------------------------------------------------------------
 nsToolkit::nsToolkit()
 {
+  MOZ_COUNT_CTOR(nsToolkit);
 }
 
 //-------------------------------------------------------------------------
 // destructor
 //-------------------------------------------------------------------------
 nsToolkit::~nsToolkit()
 {
+  MOZ_COUNT_DTOR(nsToolkit);
   // Remove the TLS reference to the toolkit...
   PR_SetThreadPrivate(gToolkitTLSIndex, nsnull);
 }
 
 //-------------------------------------------------------------------------
 // nsISupports implementation macro
 //-------------------------------------------------------------------------
 NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit)
--- a/widget/src/windows/nsToolkit.cpp
+++ b/widget/src/windows/nsToolkit.cpp
@@ -112,16 +112,17 @@ void RunPump(void* arg)
 
 //-------------------------------------------------------------------------
 //
 // constructor
 //
 //-------------------------------------------------------------------------
 nsToolkit::nsToolkit()  
 {
+    MOZ_COUNT_CTOR(nsToolkit);
     mGuiThread  = NULL;
     mDispatchWnd = 0;
 
 #if defined(MOZ_STATIC_COMPONENT_LIBS)
     nsToolkit::Startup(GetModuleHandle(NULL));
 #endif
 
     gMouseTrailer = new MouseTrailer();
@@ -130,16 +131,17 @@ nsToolkit::nsToolkit()
 
 //-------------------------------------------------------------------------
 //
 // destructor
 //
 //-------------------------------------------------------------------------
 nsToolkit::~nsToolkit()
 {
+    MOZ_COUNT_DTOR(nsToolkit);
     NS_PRECONDITION(::IsWindow(mDispatchWnd), "Invalid window handle");
 
     // Destroy the Dispatch Window
     ::DestroyWindow(mDispatchWnd);
     mDispatchWnd = NULL;
 
     // Remove the TLS reference to the toolkit...
     PR_SetThreadPrivate(gToolkitTLSIndex, nsnull);
@@ -188,19 +190,19 @@ nsToolkit::Shutdown()
     //nsUXThemeData::Teardown();
     //VERIFY(::UnregisterClass("nsToolkitClass", nsToolkit::mDllInstance));
     ::UnregisterClassW(L"nsToolkitClass", nsToolkit::mDllInstance);
 }
 
 void
 nsToolkit::StartAllowingD3D9()
 {
-  nsIToolkit *toolkit;
-  NS_GetCurrentToolkit(&toolkit);
-  static_cast<nsToolkit*>(toolkit)->mD3D9Timer->Cancel();
+  nsRefPtr<nsIToolkit> toolkit;
+  NS_GetCurrentToolkit(getter_AddRefs(toolkit));
+  static_cast<nsToolkit*>(toolkit.get())->mD3D9Timer->Cancel();
   nsWindow::StartAllowingD3D9(false);
 }
 
 //-------------------------------------------------------------------------
 //
 // Register the window class for the internal window and create the window
 //
 //-------------------------------------------------------------------------
--- a/widget/src/windows/nsWindowGfx.cpp
+++ b/widget/src/windows/nsWindowGfx.cpp
@@ -376,17 +376,17 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
               (IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH32) ||
                IsRenderMode(gfxWindowsPlatform::RENDER_IMAGE_STRETCH24)))
           {
             gfxIntSize surfaceSize(ps.rcPaint.right - ps.rcPaint.left,
                                    ps.rcPaint.bottom - ps.rcPaint.top);
 
             if (!EnsureSharedSurfaceSize(surfaceSize)) {
               NS_ERROR("Couldn't allocate a shared image surface!");
-              return NS_ERROR_FAILURE;
+              return false;
             }
 
             // don't use the shared surface directly; instead, create a new one
             // that just reuses its buffer.
             targetSurfaceImage = new gfxImageSurface(sSharedSurfaceData.get(),
                                                      surfaceSize,
                                                      surfaceSize.width * 4,
                                                      gfxASurface::ImageFormatRGB24);
@@ -394,17 +394,17 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
             if (targetSurfaceImage && !targetSurfaceImage->CairoStatus()) {
               targetSurfaceImage->SetDeviceOffset(gfxPoint(-ps.rcPaint.left, -ps.rcPaint.top));
               targetSurface = targetSurfaceImage;
             }
           }
 
           if (!targetSurface) {
             NS_ERROR("Invalid RenderMode!");
-            return NS_ERROR_FAILURE;
+            return false;
           }
 
           nsRefPtr<gfxContext> thebesContext = new gfxContext(targetSurface);
           if (IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D)) {
             const nsIntRect* r;
             for (nsIntRegionRectIterator iter(event.region);
                  (r = iter.Next()) != nsnull;) {
               thebesContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height), true);
--- a/widget/src/xpwidgets/nsBaseAppShell.cpp
+++ b/widget/src/xpwidgets/nsBaseAppShell.cpp
@@ -31,24 +31,24 @@
  * 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 "base/message_loop.h"
+
 #include "nsBaseAppShell.h"
 #include "nsThreadUtils.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/Services.h"
 
-#include "base/message_loop.h"
-
 // When processing the next thread event, the appshell may process native
 // events (if not in performance mode), which can result in suppressing the
 // next thread event for at most this many ticks:
 #define THREAD_EVENT_STARVATION_LIMIT PR_MillisecondsToInterval(20)
 
 NS_IMPL_THREADSAFE_ISUPPORTS3(nsBaseAppShell, nsIAppShell, nsIThreadObserver,
                               nsIObserver)
 
--- a/xpcom/glue/nsTArray-inl.h
+++ b/xpcom/glue/nsTArray-inl.h
@@ -50,16 +50,89 @@ template<class Alloc>
 nsTArray_base<Alloc>::~nsTArray_base() {
   if (mHdr != EmptyHdr() && !UsesAutoArrayBuffer()) {
     Alloc::Free(mHdr);
   }
   MOZ_COUNT_DTOR(nsTArray_base);
 }
 
 template<class Alloc>
+nsTArrayHeader* nsTArray_base<Alloc>::GetAutoArrayBufferUnsafe(size_t elemAlign) {
+  // Assuming |this| points to an nsAutoArray, we want to get a pointer to
+  // mAutoBuf.  So just cast |this| to nsAutoArray* and read &mAutoBuf!
+
+  void* autoBuf = &reinterpret_cast<nsAutoArrayBase<nsTArray<PRUint32>, 1>*>(this)->mAutoBuf;
+
+  // If we're on a 32-bit system and elemAlign is 8, we need to adjust our
+  // pointer to take into account the extra alignment in the auto array.
+
+  // Check that the auto array is padded as we expect.
+  PR_STATIC_ASSERT(sizeof(void*) != 4 ||
+                   (MOZ_ALIGNOF(mozilla::AlignedElem<8>) == 8 &&
+                    sizeof(nsAutoTArray<mozilla::AlignedElem<8>, 1>) ==
+                      sizeof(void*) + sizeof(nsTArrayHeader) +
+                      4 + sizeof(mozilla::AlignedElem<8>)));
+
+  // We don't support alignments greater than 8 bytes.
+  NS_ABORT_IF_FALSE(elemAlign <= 4 || elemAlign == 8, "unsupported alignment.");
+  if (sizeof(void*) == 4 && elemAlign == 8) {
+    autoBuf = reinterpret_cast<char*>(autoBuf) + 4;
+  }
+
+  return reinterpret_cast<Header*>(autoBuf);
+}
+
+template<class Alloc>
+bool nsTArray_base<Alloc>::UsesAutoArrayBuffer() {
+  if (!mHdr->mIsAutoArray) {
+    return PR_FALSE;
+  }
+
+  // This is nuts.  If we were sane, we'd pass elemAlign as a parameter to
+  // this function.  Unfortunately this function is called in nsTArray_base's
+  // destructor, at which point we don't know elem_type's alignment.
+  //
+  // We'll fall on our face and return true when we should say false if
+  //
+  //   * we're not using our auto buffer,
+  //   * elemAlign == 4, and
+  //   * mHdr == GetAutoArrayBuffer(8).
+  //
+  // This could happen if |*this| lives on the heap and malloc allocated our
+  // buffer on the heap adjacent to |*this|.
+  //
+  // However, we can show that this can't happen.  If |this| is an auto array
+  // (as we ensured at the beginning of the method), GetAutoArrayBuffer(8)
+  // always points to memory owned by |*this|, because (as we assert below)
+  //
+  //   * GetAutoArrayBuffer(8) is at most 4 bytes past GetAutoArrayBuffer(4), and 
+  //   * sizeof(nsTArrayHeader) > 4.
+  //
+  // Since nsAutoTArray always contains an nsTArrayHeader,
+  // GetAutoArrayBuffer(8) will always point inside the auto array object,
+  // even if it doesn't point at the beginning of the header.
+  //
+  // Note that this means that we can't store elements with alignment 16 in an
+  // nsTArray, because GetAutoArrayBuffer(16) could lie outside the memory
+  // owned by this nsAutoTArray.  We statically assert that elem_type's
+  // alignment is 8 bytes or less in nsAutoArrayBase.
+
+  PR_STATIC_ASSERT(sizeof(nsTArrayHeader) > 4);
+
+#ifdef DEBUG
+  PRPtrdiff diff = reinterpret_cast<char*>(GetAutoArrayBuffer(8)) -
+                   reinterpret_cast<char*>(GetAutoArrayBuffer(4));
+  NS_ABORT_IF_FALSE(diff >= 0 && diff <= 4, "GetAutoArrayBuffer doesn't do what we expect.");
+#endif
+
+  return mHdr == GetAutoArrayBuffer(4) || mHdr == GetAutoArrayBuffer(8);
+}
+
+
+template<class Alloc>
 bool
 nsTArray_base<Alloc>::EnsureCapacity(size_type capacity, size_type elemSize) {
   // This should be the most common case so test this first
   if (capacity <= mHdr->mCapacity)
     return PR_TRUE;
 
   // If the requested memory allocation exceeds size_type(-1)/2, then
   // our doubling algorithm may not be able to allocate it.
@@ -134,27 +207,27 @@ nsTArray_base<Alloc>::EnsureCapacity(siz
 
   mHdr = header;
 
   return PR_TRUE;
 }
 
 template<class Alloc>
 void
-nsTArray_base<Alloc>::ShrinkCapacity(size_type elemSize) {
+nsTArray_base<Alloc>::ShrinkCapacity(size_type elemSize, size_t elemAlign) {
   if (mHdr == EmptyHdr() || UsesAutoArrayBuffer())
     return;
 
   if (mHdr->mLength >= mHdr->mCapacity)  // should never be greater than...
     return;
 
   size_type length = Length();
 
-  if (IsAutoArray() && GetAutoArrayBuffer()->mCapacity >= length) {
-    Header* header = GetAutoArrayBuffer();
+  if (IsAutoArray() && GetAutoArrayBuffer(elemAlign)->mCapacity >= length) {
+    Header* header = GetAutoArrayBuffer(elemAlign);
 
     // Copy data, but don't copy the header to avoid overwriting mCapacity
     header->mLength = length;
     memcpy(header + 1, mHdr + 1, length * elemSize);
 
     Alloc::Free(mHdr);
     mHdr = header;
     return;
@@ -174,27 +247,27 @@ nsTArray_base<Alloc>::ShrinkCapacity(siz
   mHdr = static_cast<Header*>(ptr);
   mHdr->mCapacity = length;
 }
 
 template<class Alloc>
 void
 nsTArray_base<Alloc>::ShiftData(index_type start,
                                 size_type oldLen, size_type newLen,
-                                size_type elemSize) {
+                                size_type elemSize, size_t elemAlign) {
   if (oldLen == newLen)
     return;
 
   // Determine how many elements need to be shifted
   size_type num = mHdr->mLength - (start + oldLen);
 
   // Compute the resulting length of the array
   mHdr->mLength += newLen - oldLen;
   if (mHdr->mLength == 0) {
-    ShrinkCapacity(elemSize);
+    ShrinkCapacity(elemSize, elemAlign);
   } else {
     // Maybe nothing needs to be shifted
     if (num == 0)
       return;
     // Perform shift (change units to bytes first)
     start *= elemSize;
     newLen *= elemSize;
     oldLen *= elemSize;
@@ -202,76 +275,79 @@ nsTArray_base<Alloc>::ShiftData(index_ty
     char *base = reinterpret_cast<char*>(mHdr + 1) + start;
     memmove(base + newLen, base + oldLen, num);
   }
 }
 
 template<class Alloc>
 bool
 nsTArray_base<Alloc>::InsertSlotsAt(index_type index, size_type count,
-                                    size_type elementSize)  {
+                                    size_type elementSize, size_t elemAlign)  {
   NS_ASSERTION(index <= Length(), "Bogus insertion index");
   size_type newLen = Length() + count;
 
   EnsureCapacity(newLen, elementSize);
 
   // Check for out of memory conditions
   if (Capacity() < newLen)
     return PR_FALSE;
 
   // Move the existing elements as needed.  Note that this will
   // change our mLength, so no need to call IncrementLength.
-  ShiftData(index, 0, count, elementSize);
+  ShiftData(index, 0, count, elementSize, elemAlign);
       
   return PR_TRUE;
 }
 
 // nsTArray_base::IsAutoArrayRestorer is an RAII class which takes
 // |nsTArray_base &array| in its constructor.  When it's destructed, it ensures
 // that
 //
 //   * array.mIsAutoArray has the same value as it did when we started, and
 //   * if array has an auto buffer and mHdr would otherwise point to sEmptyHdr,
 //     array.mHdr points to array's auto buffer.
 
 template<class Alloc>
 nsTArray_base<Alloc>::IsAutoArrayRestorer::IsAutoArrayRestorer(
-  nsTArray_base<Alloc> &array) 
+  nsTArray_base<Alloc> &array,
+  size_t elemAlign) 
   : mArray(array),
+    mElemAlign(elemAlign),
     mIsAuto(array.IsAutoArray())
 {
 }
 
 template<class Alloc>
 nsTArray_base<Alloc>::IsAutoArrayRestorer::~IsAutoArrayRestorer() {
   // Careful: We don't want to set mIsAutoArray = 1 on sEmptyHdr.
   if (mIsAuto && mArray.mHdr == mArray.EmptyHdr()) {
     // Call GetAutoArrayBufferUnsafe() because GetAutoArrayBuffer() asserts
     // that mHdr->mIsAutoArray is true, which surely isn't the case here.
-    mArray.mHdr = mArray.GetAutoArrayBufferUnsafe();
+    mArray.mHdr = mArray.GetAutoArrayBufferUnsafe(mElemAlign);
     mArray.mHdr->mLength = 0;
   }
   else {
     mArray.mHdr->mIsAutoArray = mIsAuto;
   }
 }
 
 template<class Alloc>
 template<class Allocator>
 bool
 nsTArray_base<Alloc>::SwapArrayElements(nsTArray_base<Allocator>& other,
-                                        size_type elemSize) {
+                                        size_type elemSize,
+                                        size_t elemAlign) {
 
   // EnsureNotUsingAutoArrayBuffer will set mHdr = sEmptyHdr even if we have an
   // auto buffer.  We need to point mHdr back to our auto buffer before we
   // return, otherwise we'll forget that we have an auto buffer at all!
   // IsAutoArrayRestorer takes care of this for us.
 
-  IsAutoArrayRestorer ourAutoRestorer(*this);
-  typename nsTArray_base<Allocator>::IsAutoArrayRestorer otherAutoRestorer(other);
+  IsAutoArrayRestorer ourAutoRestorer(*this, elemAlign);
+  typename nsTArray_base<Allocator>::IsAutoArrayRestorer otherAutoRestorer(other, elemAlign);
 
   // If neither array uses an auto buffer which is big enough to store the
   // other array's elements, then ensure that both arrays use malloc'ed storage
   // and swap their mHdr pointers.
   if ((!UsesAutoArrayBuffer() || Capacity() < other.Length()) &&
       (!other.UsesAutoArrayBuffer() || other.Capacity() < Length())) {
 
     if (!EnsureNotUsingAutoArrayBuffer(elemSize) ||
@@ -299,17 +375,18 @@ nsTArray_base<Alloc>::SwapArrayElements(
 
   if (!EnsureCapacity(other.Length(), elemSize) ||
       !other.EnsureCapacity(Length(), elemSize)) {
     return PR_FALSE;
   }
 
   // The EnsureCapacity calls above shouldn't have caused *both* arrays to
   // switch from their auto buffers to malloc'ed space.
-  NS_ABORT_IF_FALSE(UsesAutoArrayBuffer() || other.UsesAutoArrayBuffer(),
+  NS_ABORT_IF_FALSE(UsesAutoArrayBuffer() ||
+                    other.UsesAutoArrayBuffer(),
                     "One of the arrays should be using its auto buffer.");
 
   size_type smallerLength = NS_MIN(Length(), other.Length());
   size_type largerLength = NS_MAX(Length(), other.Length());
   void *smallerElements, *largerElements;
   if (Length() <= other.Length()) {
     smallerElements = Hdr() + 1;
     largerElements = other.Hdr() + 1;
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -42,16 +42,17 @@
 #include <string.h>
 
 #include "prtypes.h"
 #include "nsAlgorithm.h"
 #include "nscore.h"
 #include "nsQuickSort.h"
 #include "nsDebug.h"
 #include "nsTraceRefcnt.h"
+#include "mozilla/Util.h"
 #include NEW_H
 
 //
 // NB: nsTArray assumes that your "T" can be memmove()d.  This is in
 // contrast to STL containers, which follow C++
 // construction/destruction rules.
 //
 // Don't use nsTArray if your "T" can't be memmove()d correctly.
@@ -195,94 +196,88 @@ protected:
   // Resize the storage if necessary to achieve the requested capacity.
   // @param capacity     The requested number of array elements.
   // @param elemSize     The size of an array element.
   // @return False if insufficient memory is available; true otherwise.
   bool EnsureCapacity(size_type capacity, size_type elemSize);
 
   // Resize the storage to the minimum required amount.
   // @param elemSize     The size of an array element.
-  void ShrinkCapacity(size_type elemSize);
+  // @param elemAlign    The alignment in bytes of an array element.
+  void ShrinkCapacity(size_type elemSize, size_t elemAlign);
     
   // This method may be called to resize a "gap" in the array by shifting
   // elements around.  It updates mLength appropriately.  If the resulting
   // array has zero elements, then the array's memory is free'd.
   // @param start        The starting index of the gap.
   // @param oldLen       The current length of the gap.
   // @param newLen       The desired length of the gap.
   // @param elemSize     The size of an array element.
+  // @param elemAlign    The alignment in bytes of an array element.
   void ShiftData(index_type start, size_type oldLen, size_type newLen,
-                 size_type elemSize);
+                 size_type elemSize, size_t elemAlign);
 
   // This method increments the length member of the array's header.
   // Note that mHdr may actually be sEmptyHdr in the case where a
   // zero-length array is inserted into our array. But then n should
   // always be 0.
   void IncrementLength(PRUint32 n) {
     NS_ASSERTION(mHdr != EmptyHdr() || n == 0, "bad data pointer");
     mHdr->mLength += n;
   }
 
   // This method inserts blank slots into the array.
   // @param index the place to insert the new elements. This must be no
   //              greater than the current length of the array.
   // @param count the number of slots to insert
   // @param elementSize the size of an array element.
+  // @param elemAlign the alignment in bytes of an array element.
   bool InsertSlotsAt(index_type index, size_type count,
-                       size_type elementSize);
+                       size_type elementSize, size_t elemAlign);
 
 protected:
   template<class Allocator>
   bool SwapArrayElements(nsTArray_base<Allocator>& other,
-                           size_type elemSize);
+                           size_type elemSize,
+                           size_t elemAlign);
 
   // This is an RAII class used in SwapArrayElements.
   class IsAutoArrayRestorer {
     public:
-      IsAutoArrayRestorer(nsTArray_base<Alloc> &array);
+      IsAutoArrayRestorer(nsTArray_base<Alloc> &array, size_t elemAlign);
       ~IsAutoArrayRestorer();
 
     private:
       nsTArray_base<Alloc> &mArray;
+      size_t mElemAlign;
       bool mIsAuto;
   };
 
   // Helper function for SwapArrayElements. Ensures that if the array
   // is an nsAutoTArray that it doesn't use the built-in buffer.
   bool EnsureNotUsingAutoArrayBuffer(size_type elemSize);
 
   // Returns true if this nsTArray is an nsAutoTArray with a built-in buffer.
   bool IsAutoArray() {
     return mHdr->mIsAutoArray;
   }
 
-  // Dummy struct to get the compiler to simulate the alignment of
-  // nsAutoTArray's and nsAutoTPtrArray's mAutoBuf.
-  struct AutoArray {
-    Header *mHdr;
-    PRUint64 aligned;
-  };
-
   // Returns a Header for the built-in buffer of this nsAutoTArray.
-  Header* GetAutoArrayBuffer() {
+  Header* GetAutoArrayBuffer(size_t elemAlign) {
     NS_ASSERTION(IsAutoArray(), "Should be an auto array to call this");
-    return GetAutoArrayBufferUnsafe();
+    return GetAutoArrayBufferUnsafe(elemAlign);
   }
 
   // Returns a Header for the built-in buffer of this nsAutoTArray, but doesn't
   // assert that we are an nsAutoTArray.
-  Header* GetAutoArrayBufferUnsafe() {
-    return reinterpret_cast<Header*>(&(reinterpret_cast<AutoArray*>(&mHdr))->aligned);
-  }
+  Header* GetAutoArrayBufferUnsafe(size_t elemAlign);
 
   // Returns true if this is an nsAutoTArray and it currently uses the
   // built-in buffer to store its elements.
-  bool UsesAutoArrayBuffer() {
-    return mHdr->mIsAutoArray && mHdr == GetAutoArrayBuffer();
-  }
+  bool UsesAutoArrayBuffer();
 
   // The array's elements (prefixed with a Header).  This pointer is never
   // null.  If the array is empty, then this will point to sEmptyHdr.
   Header *mHdr;
 
   Header* Hdr() const { 
     return mHdr;
   }
@@ -678,17 +673,17 @@ public:
   //                  the operation failed due to insufficient memory.
   template<class Item>
   elem_type *ReplaceElementsAt(index_type start, size_type count,
                                const Item* array, size_type arrayLen) {
     // Adjust memory allocation up-front to catch errors.
     if (!this->EnsureCapacity(Length() + arrayLen - count, sizeof(elem_type)))
       return nsnull;
     DestructRange(start, count);
-    this->ShiftData(start, count, arrayLen, sizeof(elem_type));
+    this->ShiftData(start, count, arrayLen, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
     AssignRange(start, arrayLen, array);
     return Elements() + start;
   }
 
   // A variation on the ReplaceElementsAt method defined above.
   template<class Item>
   elem_type *ReplaceElementsAt(index_type start, size_type count,
                                const nsTArray<Item>& array) {
@@ -728,17 +723,17 @@ public:
   }
 
   // Insert a new element without copy-constructing. This is useful to avoid
   // temporaries.
   // @return A pointer to the newly inserted element, or null on OOM.
   elem_type* InsertElementAt(index_type index) {
     if (!this->EnsureCapacity(Length() + 1, sizeof(elem_type)))
       return nsnull;
-    this->ShiftData(index, 0, 1, sizeof(elem_type));
+    this->ShiftData(index, 0, 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
     elem_type *elem = Elements() + index;
     elem_traits::Construct(elem);
     return elem;
   }
 
   // This method searches for the least index of the greatest
   // element less than or equal to |item|.  If |item| is inserted at
   // this index, the array will remain sorted.  True is returned iff
@@ -876,28 +871,28 @@ public:
   elem_type *MoveElementsFrom(nsTArray<Item, Allocator>& array) {
     NS_PRECONDITION(&array != this, "argument must be different array");
     index_type len = Length();
     index_type otherLen = array.Length();
     if (!this->EnsureCapacity(len + otherLen, sizeof(elem_type)))
       return nsnull;
     memcpy(Elements() + len, array.Elements(), otherLen * sizeof(elem_type));
     this->IncrementLength(otherLen);      
-    array.ShiftData(0, otherLen, 0, sizeof(elem_type));
+    array.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
     return Elements() + len;
   }
 
   // This method removes a range of elements from this array.
   // @param start  The starting index of the elements to remove.
   // @param count  The number of elements to remove.
   void RemoveElementsAt(index_type start, size_type count) {
     NS_ASSERTION(count == 0 || start < Length(), "Invalid start index");
     NS_ASSERTION(start + count <= Length(), "Invalid length");
     DestructRange(start, count);
-    this->ShiftData(start, count, 0, sizeof(elem_type));
+    this->ShiftData(start, count, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
   }
 
   // A variation on the RemoveElementsAt method defined above.
   void RemoveElementAt(index_type index) {
     RemoveElementsAt(index, 1);
   }
 
   // A variation on the RemoveElementsAt method defined above.
@@ -947,17 +942,17 @@ public:
   bool RemoveElementSorted(const Item& item) {
     return RemoveElementSorted(item, nsDefaultComparator<elem_type, Item>());
   }
 
   // This method causes the elements contained in this array and the given
   // array to be swapped.
   template<class Allocator>
   bool SwapElements(nsTArray<E, Allocator>& other) {
-    return this->SwapArrayElements(other, sizeof(elem_type));
+    return this->SwapArrayElements(other, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
   }
 
   //
   // Allocation
   //
 
   // This method may increase the capacity of this array object by the
   // specified amount.  This method may be called in advance of several
@@ -1015,17 +1010,17 @@ public:
   }
 
   // This method inserts elements into the array, constructing
   // them using elem_type's default constructor.
   // @param index the place to insert the new elements. This must be no
   //              greater than the current length of the array.
   // @param count the number of elements to insert
   elem_type *InsertElementsAt(index_type index, size_type count) {
-    if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type))) {
+    if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
       return nsnull;
     }
 
     // Initialize the extra array elements
     elem_type *iter = Elements() + index, *end = iter + count;
     for (; iter != end; ++iter) {
       elem_traits::Construct(iter);
     }
@@ -1038,32 +1033,32 @@ public:
   // happens to match the Item type).
   // @param index the place to insert the new elements. This must be no
   //              greater than the current length of the array.
   // @param count the number of elements to insert.
   // @param item the value to use when constructing the new elements.
   template<class Item>
   elem_type *InsertElementsAt(index_type index, size_type count,
                               const Item& item) {
-    if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type))) {
+    if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
       return nsnull;
     }
 
     // Initialize the extra array elements
     elem_type *iter = Elements() + index, *end = iter + count;
     for (; iter != end; ++iter) {
       elem_traits::Construct(iter, item);
     }
 
     return Elements() + index;
   }
 
   // This method may be called to minimize the memory used by this array.
   void Compact() {
-    ShrinkCapacity(sizeof(elem_type));
+    ShrinkCapacity(sizeof(elem_type), MOZ_ALIGNOF(elem_type));
   }
 
   //
   // Sorting
   //
 
   // This method sorts the elements of the array.  It uses the LessThan
   // method defined on the given Comparator object to collate elements.
@@ -1103,17 +1098,17 @@ public:
     MakeHeap(nsDefaultComparator<elem_type, elem_type>());
   }
 
   // Adds an element to the heap
   // @param item The item to add
   // @param comp The Comparator used to sift-up the item
   template<class Item, class Comparator>
   elem_type *PushHeap(const Item& item, const Comparator& comp) {
-    if (!base_type::InsertSlotsAt(Length(), 1, sizeof(elem_type))) {
+    if (!base_type::InsertSlotsAt(Length(), 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) {
       return nsnull;
     }
     // Sift up the new node
     elem_type *elem = Elements();
     index_type index = Length() - 1;
     index_type parent_index = (index - 1) / 2;
     while (index && comp.LessThan(elem[parent_index], item)) {
       elem[index] = elem[parent_index];
@@ -1233,17 +1228,16 @@ public:
   typedef typename base_type::size_type            size_type;
  
   InfallibleTArray() {}
   explicit InfallibleTArray(size_type capacity) : base_type(capacity) {}
   InfallibleTArray(const InfallibleTArray& other) : base_type(other) {}
 };
 #endif
 
-
 template<class TArrayBase, PRUint32 N>
 class nsAutoArrayBase : public TArrayBase
 {
 public:
   typedef TArrayBase base_type;
   typedef typename base_type::Header Header;
   typedef typename base_type::elem_type elem_type;
 
@@ -1257,45 +1251,74 @@ protected:
   // copy-constructors will call nsAutoArrayBase's implicit copy-constructor,
   // which won't call Init() and set up the auto buffer!
   nsAutoArrayBase(const TArrayBase &aOther) {
     Init();
     AppendElements(aOther);
   }
 
 private:
+  // nsTArray_base casts itself as an nsAutoArrayBase in order to get a pointer
+  // to mAutoBuf.
+  template<class Allocator>
+  friend class nsTArray_base;
+
   void Init() {
+    // We can't handle alignments greater than 8; see
+    // nsTArray_base::UsesAutoArrayBuffer().
+    PR_STATIC_ASSERT(MOZ_ALIGNOF(elem_type) <= 8);
+
     *base_type::PtrToHdr() = reinterpret_cast<Header*>(&mAutoBuf);
     base_type::Hdr()->mLength = 0;
     base_type::Hdr()->mCapacity = N;
     base_type::Hdr()->mIsAutoArray = 1;
 
-    NS_ASSERTION(base_type::GetAutoArrayBuffer() ==
+    NS_ASSERTION(base_type::GetAutoArrayBuffer(MOZ_ALIGNOF(elem_type)) ==
                  reinterpret_cast<Header*>(&mAutoBuf),
                  "GetAutoArrayBuffer needs to be fixed");
   }
 
+  // Declare mAutoBuf aligned to the maximum of the header's alignment and
+  // elem_type's alignment.  We need to use a union rather than
+  // MOZ_ALIGNED_DECL because GCC is picky about what goes into
+  // __attribute__((aligned(foo))).
   union {
-    char mAutoBuf[sizeof(Header) + N * sizeof(elem_type)];
-    PRUint64 dummy;
+    char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)];
+    mozilla::AlignedElem<PR_MAX(MOZ_ALIGNOF(Header), MOZ_ALIGNOF(elem_type))> mAlign;
   };
 };
 
 template<class E, PRUint32 N, class Alloc=nsTArrayDefaultAllocator>
 class nsAutoTArray : public nsAutoArrayBase<nsTArray<E, Alloc>, N>
 {
 public:
   nsAutoTArray() {}
 
   template<typename Allocator>
   nsAutoTArray(const nsTArray<E, Allocator>& other) {
     AppendElements(other);
   }
 };
 
+// Assert that nsAutoTArray doesn't have any extra padding inside.
+//
+// It's important that the data stored in this auto array takes up a multiple of
+// 8 bytes; e.g. nsAutoTArray<PRUint32, 1> wouldn't work.  Since nsAutoTArray
+// contains a pointer, its size must be a multiple of alignof(void*).  (This is
+// because any type may be placed into an array, and there's no padding between
+// elements of an array.)  The compiler pads the end of the structure to
+// enforce this rule.
+//
+// If we used nsAutoTArray<PRUint32, 1> below, this assertion would fail on a
+// 64-bit system, where the compiler inserts 4 bytes of padding at the end of
+// the auto array to make its size a multiple of alignof(void*) == 8 bytes.
+
+PR_STATIC_ASSERT(sizeof(nsAutoTArray<PRUint32, 2>) ==
+                 sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(PRUint32) * 2);
+
 template<class E, PRUint32 N>
 class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
 {
 public:
   AutoFallibleTArray() {}
 
   template<typename Allocator>
   AutoFallibleTArray(const nsTArray<E, Allocator>& other) {