TArray-allocator
author Benjamin Smedberg <benjamin@smedbergs.us>
Sat, 26 Jul 2008 22:49:39 -0400
changeset 167 a4da40849f5436e629c5732f4368c6c48189637f
parent 96 91c1b7c9ad098a4138c70c9203c96ff5f7beb920
permissions -rw-r--r--
State as of now

* * *

diff --git a/content/html/content/public/nsIForm.h b/content/html/content/public/nsIForm.h
--- a/content/html/content/public/nsIForm.h
+++ b/content/html/content/public/nsIForm.h
@@ -39,11 +39,11 @@
 
 #include "nsISupports.h"
 #include "nsAString.h"
+#include "nsTArray.h"
 
 class nsIFormControl;
 class nsISimpleEnumerator;
 class nsIURI;
-template<class T> class nsTArray;
 
 #define NS_FORM_METHOD_GET  0
 #define NS_FORM_METHOD_POST 1
diff --git a/layout/generic/nsIAnonymousContentCreator.h b/layout/generic/nsIAnonymousContentCreator.h
--- a/layout/generic/nsIAnonymousContentCreator.h
+++ b/layout/generic/nsIAnonymousContentCreator.h
@@ -45,10 +45,10 @@
 
 #include "nsISupports.h"
 #include "nsIContent.h"
+#include "nsTArray.h"
 
 class nsPresContext;
 class nsIFrame;
-template <class T> class nsTArray;
 
 // {7568a516-3831-4db4-88a7-a42578acc136}
 #define NS_IANONYMOUS_CONTENT_CREATOR_IID \
diff --git a/toolkit/components/places/src/nsMaybeWeakPtr.cpp b/toolkit/components/places/src/nsMaybeWeakPtr.cpp
--- a/toolkit/components/places/src/nsMaybeWeakPtr.cpp
+++ b/toolkit/components/places/src/nsMaybeWeakPtr.cpp
@@ -62,7 +62,7 @@ nsMaybeWeakPtr_base::GetValueAs(const ns
 }
 
 /* static */ nsresult
-nsMaybeWeakPtrArray_base::AppendWeakElementBase(nsTArray_base *aArray,
+nsMaybeWeakPtrArray_base::AppendWeakElementBase(nsTArray_base<CAllocator> *aArray,
                                                 nsISupports *aElement,
                                                 PRBool aOwnsWeak)
 {
@@ -86,7 +86,7 @@ nsMaybeWeakPtrArray_base::AppendWeakElem
 }
 
 /* static */ nsresult
-nsMaybeWeakPtrArray_base::RemoveWeakElementBase(nsTArray_base *aArray,
+nsMaybeWeakPtrArray_base::RemoveWeakElementBase(nsTArray_base<CAllocator> *aArray,
                                                 nsISupports *aElement)
 {
   isupports_type *array = static_cast<isupports_type*>(aArray);
diff --git a/toolkit/components/places/src/nsMaybeWeakPtr.h b/toolkit/components/places/src/nsMaybeWeakPtr.h
--- a/toolkit/components/places/src/nsMaybeWeakPtr.h
+++ b/toolkit/components/places/src/nsMaybeWeakPtr.h
@@ -100,9 +100,9 @@ class nsMaybeWeakPtrArray_base
 class nsMaybeWeakPtrArray_base
 {
 protected:
-  static nsresult AppendWeakElementBase(nsTArray_base *aArray,
+  static nsresult AppendWeakElementBase(nsTArray_base<CAllocator> *aArray,
                                         nsISupports *aElement, PRBool aWeak);
-  static nsresult RemoveWeakElementBase(nsTArray_base *aArray,
+  static nsresult RemoveWeakElementBase(nsTArray_base<CAllocator> *aArray,
                                          nsISupports *aElement);
 
   typedef nsTArray< nsMaybeWeakPtr<nsISupports> > isupports_type;
diff --git a/toolkit/components/satchel/src/nsStorageFormHistory.h b/toolkit/components/satchel/src/nsStorageFormHistory.h
--- a/toolkit/components/satchel/src/nsStorageFormHistory.h
+++ b/toolkit/components/satchel/src/nsStorageFormHistory.h
@@ -56,11 +56,11 @@
 #ifdef MOZ_MORKREADER
 #include "nsMorkReader.h"
 #endif
+#include "nsTArray.h"
 
 class nsIAutoCompleteSimpleResult;
 class nsIAutoCompleteResult;
 class nsFormHistory;
-template <class E> class nsTArray;
 
 #define NS_IFORMHISTORYPRIVATE_IID \
 {0xc4a47315, 0xaeb5, 0x4039, {0x9f, 0x34, 0x45, 0x11, 0xb3, 0xa7, 0x58, 0xdd}}
diff --git a/xpcom/glue/nsTArray.cpp b/xpcom/glue/nsTArray.cpp
deleted file mode 100644
--- a/xpcom/glue/nsTArray.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is C++ array template.
- *
- * The Initial Developer of the Original Code is Google Inc.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Darin Fisher <darin@meer.net>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include <string.h>
-#include "nsTArray.h"
-#include "nsXPCOM.h"
-#include "nsDebug.h"
-
-nsTArray_base::Header nsTArray_base::sEmptyHdr = { 0, 0, 0 };
-
-nsTArray_base::nsTArray_base()
-  : mHdr(&sEmptyHdr) {
-  MOZ_COUNT_CTOR(nsTArray_base);
-}
-
-nsTArray_base::~nsTArray_base() {
-  if (mHdr != &sEmptyHdr && !UsesAutoArrayBuffer()) {
-    NS_Free(mHdr);
-  }
-  MOZ_COUNT_DTOR(nsTArray_base);
-}
-
-PRBool
-nsTArray_base::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.  Additionally we
-  // couldn't fit in the Header::mCapacity member. Just bail out in cases
-  // like that.  We don't want to be allocating 2 GB+ arrays anyway.
-  if (capacity * elemSize > size_type(-1)/2) {
-    NS_ERROR("Attempting to allocate excessively large array");
-    return PR_FALSE;
-  }
-
-  if (mHdr == &sEmptyHdr) {
-    // NS_Alloc new data
-    Header *header = static_cast<Header*>
-                                (NS_Alloc(sizeof(Header) + capacity * elemSize));
-    if (!header)
-      return PR_FALSE;
-    header->mLength = 0;
-    header->mCapacity = capacity;
-    header->mIsAutoArray = 0;
-    mHdr = header;
-    
-    return PR_TRUE;
-  }
-
-  // Use doubling algorithm when forced to increase available capacity.
-  capacity = PR_MAX(capacity, mHdr->mCapacity << 1);
-
-  Header *header;
-  if (UsesAutoArrayBuffer()) {
-    // NS_Alloc and copy
-    header = static_cast<Header*>
-                        (NS_Alloc(sizeof(Header) + capacity * elemSize));
-    if (!header)
-      return PR_FALSE;
-
-    memcpy(header, mHdr, sizeof(Header) + Length() * elemSize);
-  } else {
-    // NS_Realloc existing data
-    size_type size = sizeof(Header) + capacity * elemSize;
-    header = static_cast<Header*>(NS_Realloc(mHdr, size));
-    if (!header)
-      return PR_FALSE;
-  }
-
-  header->mCapacity = capacity;
-  mHdr = header;
-
-  return PR_TRUE;
-}
-
-void
-nsTArray_base::ShrinkCapacity(size_type elemSize) {
-  if (mHdr == &sEmptyHdr || 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();
-
-    // Copy data, but don't copy the header to avoid overwriting mCapacity
-    header->mLength = length;
-    memcpy(header + 1, mHdr + 1, length * elemSize);
-
-    NS_Free(mHdr);
-    mHdr = header;
-    return;
-  }
-
-  if (length == 0) {
-    NS_ASSERTION(!IsAutoArray(), "autoarray should have fit 0 elements");
-    NS_Free(mHdr);
-    mHdr = &sEmptyHdr;
-    return;
-  }
-
-  size_type size = sizeof(Header) + length * elemSize;
-  void *ptr = NS_Realloc(mHdr, size);
-  if (!ptr)
-    return;
-  mHdr = static_cast<Header*>(ptr);
-  mHdr->mCapacity = length;
-}
-
-void
-nsTArray_base::ShiftData(index_type start, size_type oldLen, size_type newLen,
-                         size_type elemSize) {
-  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);
-  } else {
-    // Maybe nothing needs to be shifted
-    if (num == 0)
-      return;
-    // Perform shift (change units to bytes first)
-    start *= elemSize;
-    newLen *= elemSize;
-    oldLen *= elemSize;
-    num *= elemSize;
-    char *base = reinterpret_cast<char*>(mHdr + 1) + start;
-    memmove(base + newLen, base + oldLen, num);
-  }
-}
-
-PRBool
-nsTArray_base::InsertSlotsAt(index_type index, size_type count,
-                             size_type elementSize) {
-  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);
-      
-  return PR_TRUE;
-}
-
-PRBool
-nsTArray_base::SwapArrayElements(nsTArray_base& other, size_type elemSize)
-{
-#ifdef DEBUG
-  PRBool isAuto = IsAutoArray();
-  PRBool otherIsAuto = other.IsAutoArray();
-#endif
-
-  if (!EnsureNotUsingAutoArrayBuffer(elemSize) ||
-      !other.EnsureNotUsingAutoArrayBuffer(elemSize)) {
-    return PR_FALSE;
-  }
-
-  NS_ASSERTION(isAuto == IsAutoArray(), "lost auto info");
-  NS_ASSERTION(otherIsAuto == other.IsAutoArray(), "lost auto info");
-  NS_ASSERTION(!UsesAutoArrayBuffer() && !other.UsesAutoArrayBuffer(),
-               "both should be using an alloced buffer now");
-
-  // If the two arrays have different mIsAutoArray values (i.e. one is an
-  // autoarray and one is not) then simply switching the buffers is going to
-  // make that bit wrong. We therefore adjust these mIsAutoArray bits before
-  // switching the buffers so that once the buffers are switched the
-  // mIsAutoArray bits are right again.
-  // However, we have to watch out so that we don't set the bit on
-  // sEmptyHeader. If an array (A) uses the empty header (and the other (B)
-  // therefore must be an nsAutoTArray) we make A point to the B's autobuffer
-  // so that when the buffers are switched B points to its own autobuffer.
-
-  // Adjust mIsAutoArray flags before swapping the buffers
-  if (IsAutoArray() && !other.IsAutoArray()) {
-    if (other.mHdr == &sEmptyHdr) {
-      // Set other to use our built-in buffer so that we use it
-      // after the swap below.
-      other.mHdr = GetAutoArrayBuffer();
-      other.mHdr->mLength = 0;
-    }
-    else {
-      other.mHdr->mIsAutoArray = 1;
-    }
-    mHdr->mIsAutoArray = 0;
-  }
-  else if (!IsAutoArray() && other.IsAutoArray()) {
-    if (mHdr == &sEmptyHdr) {
-      // Set us to use other's built-in buffer so that other use it
-      // after the swap below.
-      mHdr = other.GetAutoArrayBuffer();
-      mHdr->mLength = 0;
-    }
-    else {
-      mHdr->mIsAutoArray = 1;
-    }
-    other.mHdr->mIsAutoArray = 0;
-  }
-
-  // Swap the buffers
-  Header *h = other.mHdr;
-  other.mHdr = mHdr;
-  mHdr = h;
-
-  NS_ASSERTION(isAuto == IsAutoArray(), "lost auto info");
-  NS_ASSERTION(otherIsAuto == other.IsAutoArray(), "lost auto info");
-
-  return PR_TRUE;
-}
-
-PRBool
-nsTArray_base::EnsureNotUsingAutoArrayBuffer(size_type elemSize)
-{
-  if (UsesAutoArrayBuffer()) {
-    size_type size = sizeof(Header) + Length() * elemSize;
-
-    Header* header = static_cast<Header*>(NS_Alloc(size));
-    if (!header)
-      return PR_FALSE;
-
-    memcpy(header, mHdr, size);
-    header->mCapacity = Length();
-    mHdr = header;
-  }
-  
-  return PR_TRUE;
-}
diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -43,6 +43,7 @@
 #include "nsQuickSort.h"
 #include "nsDebug.h"
 #include "nsTraceRefcnt.h"
+#include "nsAllocator.h"
 #include NEW_H
 
 //
@@ -50,7 +51,8 @@
 // directly.  It holds common implementation code that does not depend on the
 // element type of the nsTArray.
 //
-class NS_COM_GLUE nsTArray_base {
+template<class Allocator>
+class nsTArray_base {
   public:
     typedef PRUint32 size_type;
     typedef PRUint32 index_type;
@@ -253,12 +255,18 @@ class nsDefaultComparator {
 // The Equals method is used for searching, and the LessThan method is used
 // for sorting.
 //
-template<class E>
-class nsTArray : public nsTArray_base {
+template<class E, class Allocator=CAllocator>
+class nsTArray : public nsTArray_base<Allocator> {
   public:
     typedef E                        elem_type;
-    typedef nsTArray<E>              self_type;
+    typedef nsTArray<E, Allocator>   self_type;
     typedef nsTArrayElementTraits<E> elem_traits;
+    typedef typename nsTArray_base<Allocator>::size_type size_type;
+    typedef typename nsTArray_base<Allocator>::index_type index_type;
+    using nsTArray_base<Allocator>::NoIndex;
+    using nsTArray_base<Allocator>::Length;
+    using nsTArray_base<Allocator>::mHdr;
+    using nsTArray_base<Allocator>::ShrinkCapacity;
 
     //
     // Finalization method
@@ -557,8 +565,8 @@ class nsTArray : public nsTArray_base {
     }
 
     // A variation on the AppendElements method defined above.
-    template<class Item>
-    elem_type *AppendElements(const nsTArray<Item>& array) {
+    template<class Item, class ItemAllocator>
+    elem_type *AppendElements(const nsTArray<Item, ItemAllocator>& array) {
       return AppendElements(array.Elements(), array.Length());
     }
 
@@ -676,7 +684,7 @@ class nsTArray : public nsTArray_base {
     //              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 (!nsTArray_base::InsertSlotsAt(index, count, sizeof(elem_type))) {
+      if (!nsTArray_base<Allocator>::InsertSlotsAt(index, count, sizeof(elem_type))) {
         return nsnull;
       }
 
@@ -699,7 +707,7 @@ class nsTArray : public nsTArray_base {
     template<class Item>
     elem_type *InsertElementsAt(index_type index, size_type count,
                                 const Item& item) {
-      if (!nsTArray_base::InsertSlotsAt(index, count, sizeof(elem_type))) {
+      if (!nsTArray_base<Allocator>::InsertSlotsAt(index, count, sizeof(elem_type))) {
         return nsnull;
       }
 
@@ -793,4 +801,259 @@ class nsAutoTArray<E, 0> : public nsTArr
     nsAutoTArray() {}
 };
 
+template<class Allocator>
+typename nsTArray_base<Allocator>::Header
+nsTArray_base<Allocator>::sEmptyHdr = { 0, 0, 0 };
+
+template<class Allocator>
+nsTArray_base<Allocator>::nsTArray_base()
+  : mHdr(&sEmptyHdr)
+{
+  MOZ_COUNT_CTOR(nsTArray_base);
+}
+
+template<class Allocator>
+nsTArray_base<Allocator>::~nsTArray_base()
+{
+  if (mHdr != &sEmptyHdr && !UsesAutoArrayBuffer()) {
+    Allocator::Free(mHdr);
+  }
+  MOZ_COUNT_DTOR(nsTArray_base);
+}
+
+template<class Allocator>
+PRBool
+nsTArray_base<Allocator>::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.  Additionally we
+  // couldn't fit in the Header::mCapacity member. Just bail out in cases
+  // like that.  We don't want to be allocating 2 GB+ arrays anyway.
+  if (capacity * elemSize > size_type(-1)/2) {
+    NS_ERROR("Attempting to allocate excessively large array");
+    return PR_FALSE;
+  }
+
+  if (mHdr == &sEmptyHdr) {
+    // Alloc new data
+    Header *header = static_cast<Header*>
+      (Allocator::Alloc(sizeof(Header) + capacity * elemSize));
+    if (!header)
+      return PR_FALSE;
+    header->mLength = 0;
+    header->mCapacity = capacity;
+    header->mIsAutoArray = 0;
+    mHdr = header;
+    
+    return PR_TRUE;
+  }
+
+  // Use doubling algorithm when forced to increase available capacity.
+  capacity = PR_MAX(capacity, mHdr->mCapacity << 1);
+
+  Header *header;
+  if (UsesAutoArrayBuffer()) {
+    // Alloc and copy
+    header = static_cast<Header*>
+      (Allocator::Alloc(sizeof(Header) + capacity * elemSize));
+    if (!header)
+      return PR_FALSE;
+
+    memcpy(header, mHdr, sizeof(Header) + Length() * elemSize);
+  } else {
+    // Realloc existing data
+    size_type oldsize = sizeof(Header) + mHdr->mCapacity * elemSize;
+    size_type size = sizeof(Header) + capacity * elemSize;
+    header = static_cast<Header*>(Allocator::Realloc(mHdr, oldsize, size));
+    if (!header)
+      return PR_FALSE;
+  }
+
+  header->mCapacity = capacity;
+  mHdr = header;
+
+  return PR_TRUE;
+}
+
+template<class Allocator>
+void
+nsTArray_base<Allocator>::ShrinkCapacity(size_type elemSize)
+{
+  if (mHdr == &sEmptyHdr || 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();
+
+    // Copy data, but don't copy the header to avoid overwriting mCapacity
+    header->mLength = length;
+    memcpy(header + 1, mHdr + 1, length * elemSize);
+
+    Allocator::Free(mHdr);
+    mHdr = header;
+    return;
+  }
+
+  if (length == 0) {
+    NS_ASSERTION(!IsAutoArray(), "autoarray should have fit 0 elements");
+    Allocator::Free(mHdr);
+    mHdr = &sEmptyHdr;
+    return;
+  }
+
+  size_type oldsize = sizeof(Header) + mHdr->mCapacity * elemSize;
+  size_type size = sizeof(Header) + length * elemSize;
+  void *ptr = Allocator::Realloc(mHdr, oldsize, size);
+  if (!ptr)
+    return;
+  mHdr = static_cast<Header*>(ptr);
+  mHdr->mCapacity = length;
+}
+
+template<class Allocator>
+void
+nsTArray_base<Allocator>::ShiftData(index_type start, size_type oldLen,
+                                    size_type newLen, size_type elemSize)
+{
+  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);
+  } else {
+    // Maybe nothing needs to be shifted
+    if (num == 0)
+      return;
+    // Perform shift (change units to bytes first)
+    start *= elemSize;
+    newLen *= elemSize;
+    oldLen *= elemSize;
+    num *= elemSize;
+    char *base = reinterpret_cast<char*>(mHdr + 1) + start;
+    memmove(base + newLen, base + oldLen, num);
+  }
+}
+
+template<class Allocator>
+PRBool
+nsTArray_base<Allocator>::InsertSlotsAt(index_type index, size_type count,
+                                        size_type elementSize)
+{
+  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);
+      
+  return PR_TRUE;
+}
+
+template<class Allocator>
+PRBool
+nsTArray_base<Allocator>::SwapArrayElements(nsTArray_base& other,
+                                            size_type elemSize)
+{
+#ifdef DEBUG
+  PRBool isAuto = IsAutoArray();
+  PRBool otherIsAuto = other.IsAutoArray();
+#endif
+
+  if (!EnsureNotUsingAutoArrayBuffer(elemSize) ||
+      !other.EnsureNotUsingAutoArrayBuffer(elemSize)) {
+    return PR_FALSE;
+  }
+
+  NS_ASSERTION(isAuto == IsAutoArray(), "lost auto info");
+  NS_ASSERTION(otherIsAuto == other.IsAutoArray(), "lost auto info");
+  NS_ASSERTION(!UsesAutoArrayBuffer() && !other.UsesAutoArrayBuffer(),
+               "both should be using an alloced buffer now");
+
+  // If the two arrays have different mIsAutoArray values (i.e. one is an
+  // autoarray and one is not) then simply switching the buffers is going to
+  // make that bit wrong. We therefore adjust these mIsAutoArray bits before
+  // switching the buffers so that once the buffers are switched the
+  // mIsAutoArray bits are right again.
+  // However, we have to watch out so that we don't set the bit on
+  // sEmptyHeader. If an array (A) uses the empty header (and the other (B)
+  // therefore must be an nsAutoTArray) we make A point to the B's autobuffer
+  // so that when the buffers are switched B points to its own autobuffer.
+
+  // Adjust mIsAutoArray flags before swapping the buffers
+  if (IsAutoArray() && !other.IsAutoArray()) {
+    if (other.mHdr == &sEmptyHdr) {
+      // Set other to use our built-in buffer so that we use it
+      // after the swap below.
+      other.mHdr = GetAutoArrayBuffer();
+      other.mHdr->mLength = 0;
+    }
+    else {
+      other.mHdr->mIsAutoArray = 1;
+    }
+    mHdr->mIsAutoArray = 0;
+  }
+  else if (!IsAutoArray() && other.IsAutoArray()) {
+    if (mHdr == &sEmptyHdr) {
+      // Set us to use other's built-in buffer so that other use it
+      // after the swap below.
+      mHdr = other.GetAutoArrayBuffer();
+      mHdr->mLength = 0;
+    }
+    else {
+      mHdr->mIsAutoArray = 1;
+    }
+    other.mHdr->mIsAutoArray = 0;
+  }
+
+  // Swap the buffers
+  Header *h = other.mHdr;
+  other.mHdr = mHdr;
+  mHdr = h;
+
+  NS_ASSERTION(isAuto == IsAutoArray(), "lost auto info");
+  NS_ASSERTION(otherIsAuto == other.IsAutoArray(), "lost auto info");
+
+  return PR_TRUE;
+}
+
+template<class Allocator>
+PRBool
+nsTArray_base<Allocator>::EnsureNotUsingAutoArrayBuffer(size_type elemSize)
+{
+  if (UsesAutoArrayBuffer()) {
+    size_type size = sizeof(Header) + Length() * elemSize;
+
+    Header* header = static_cast<Header*>(Allocator::Alloc(size));
+    if (!header)
+      return PR_FALSE;
+
+    memcpy(header, mHdr, size);
+    header->mCapacity = Length();
+    mHdr = header;
+  }
+  
+  return PR_TRUE;
+}
+
 #endif  // nsTArray_h__
diff --git a/xpcom/glue/objs.mk b/xpcom/glue/objs.mk
--- a/xpcom/glue/objs.mk
+++ b/xpcom/glue/objs.mk
@@ -60,7 +60,6 @@ XPCOM_GLUE_SRC_LCPPSRCS =        \
   nsTHashtable.cpp               \
   nsQuickSort.cpp                \
   nsVoidArray.cpp                \
-  nsTArray.cpp                   \
   nsThreadUtils.cpp              \
   nsTObserverArray.cpp           \
   nsDeque.cpp \