Bug 819791 - Part 3: Make typeof nsTArray == typeof InfallibleTArray. r=bz
authorJustin Lebar <justin.lebar@gmail.com>
Tue, 18 Dec 2012 20:16:06 -0500
changeset 125581 1a0cd3aa1864
parent 125580 28b5c8d25fb9
child 125582 3877a7a5fdf6
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs819791
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 819791 - Part 3: Make typeof nsTArray == typeof InfallibleTArray. r=bz Also make typeof nsAutoTArray == typeof AutoInfallibleTArray and switch files to using nsTArrayForwardDeclare.h.
content/base/src/nsAttrValue.h
docshell/shistory/public/nsISHistoryInternal.idl
dom/bindings/Nullable.h
layout/generic/nsIAnonymousContentCreator.h
layout/style/nsCSSStyleSheet.h
modules/libpref/public/nsIPrefService.idl
xpcom/glue/Makefile.in
xpcom/glue/nsTArray-inl.h
xpcom/glue/nsTArray.h
xpcom/glue/nsTArrayForwardDeclare.h
--- a/content/base/src/nsAttrValue.h
+++ b/content/base/src/nsAttrValue.h
@@ -14,21 +14,21 @@
 #include "nscore.h"
 #include "nsStringGlue.h"
 #include "nsStringBuffer.h"
 #include "nsColor.h"
 #include "nsCaseTreatment.h"
 #include "nsMargin.h"
 #include "nsCOMPtr.h"
 #include "SVGAttrValueWrapper.h"
+#include "nsTArrayForwardDeclare.h"
 
 class nsAString;
 class nsIAtom;
 class nsIDocument;
-template<class E, class A> class nsTArray;
 class nsStyledElementNotElementCSSInlineStyle;
 struct MiscContainer;
 
 namespace mozilla {
 namespace css {
 class StyleRule;
 struct URLValue;
 struct ImageValue;
--- a/docshell/shistory/public/nsISHistoryInternal.idl
+++ b/docshell/shistory/public/nsISHistoryInternal.idl
@@ -13,21 +13,20 @@ interface nsIDocShell;
 
 %{C++
 #define NS_SHISTORY_INTERNAL_CID \
 { 0x9c47c121, 0x1c6e, 0x4d8f, \
   { 0xb9, 0x04, 0x3a, 0xc9, 0x68, 0x11, 0x6e, 0x88 } }
 
 #define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1"
 
-struct nsTArrayInfallibleAllocator;
-template<class E, class Alloc> class nsTArray;
+#include "nsTArrayForwardDeclare.h"
 %}
 
-[ref] native nsDocshellIDArray(nsTArray<uint64_t, nsTArrayInfallibleAllocator>);
+[ref] native nsDocshellIDArray(nsTArray<uint64_t>);
 
 [scriptable, uuid(f9348014-0239-11e2-b029-3d38e719eb2d)]
 interface nsISHistoryInternal: nsISupports
 {
   /**
    * Add a new Entry to the History List
    * @param aEntry - The entry to add
    * @param aPersist - If true this specifies that the entry should persist
--- a/dom/bindings/Nullable.h
+++ b/dom/bindings/Nullable.h
@@ -3,20 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Nullable_h
 #define mozilla_dom_Nullable_h
 
 #include "mozilla/Assertions.h"
-
-template<typename E, class Allocator> class nsTArray;
-template<typename E> class InfallibleTArray;
-template<typename E> class FallibleTArray;
+#include "nsTArrayForwardDeclare.h"
 
 namespace mozilla {
 namespace dom {
 
 // Support for nullable types
 template <typename T>
 struct Nullable
 {
@@ -64,29 +61,22 @@ public:
   }
 
   bool IsNull() const {
     return mIsNull;
   }
 
   // Make it possible to use a const Nullable of an array type with other
   // array types.
-  template<typename U, typename Allocator>
-  operator const Nullable< nsTArray<U, Allocator> >&() const {
-    // Make sure that T is ok to reinterpret to nsTArray<U, Allocator>
-    const nsTArray<U, Allocator>& arr = mValue;
+  template<typename U>
+  operator const Nullable< nsTArray<U> >&() const {
+    // Make sure that T is ok to reinterpret to nsTArray<U>
+    const nsTArray<U>& arr = mValue;
     (void)arr;
-    return *reinterpret_cast<const Nullable< nsTArray<U, Allocator> >*>(this);
-  }
-  template<typename U>
-  operator const Nullable< InfallibleTArray<U> >&() const {
-    // Make sure that T is ok to reinterpret to InfallibleTArray<U>
-    const InfallibleTArray<U>& arr = mValue;
-    (void)arr;
-    return *reinterpret_cast<const Nullable< InfallibleTArray<U> >*>(this);
+    return *reinterpret_cast<const Nullable< nsTArray<U> >*>(this);
   }
   template<typename U>
   operator const Nullable< FallibleTArray<U> >&() const {
     // Make sure that T is ok to reinterpret to FallibleTArray<U>
     const FallibleTArray<U>& arr = mValue;
     (void)arr;
     return *reinterpret_cast<const Nullable< FallibleTArray<U> >*>(this);
   }
--- a/layout/generic/nsIAnonymousContentCreator.h
+++ b/layout/generic/nsIAnonymousContentCreator.h
@@ -9,20 +9,20 @@
  */
 
 #ifndef nsIAnonymousContentCreator_h___
 #define nsIAnonymousContentCreator_h___
 
 #include "nsQueryFrame.h"
 #include "nsIContent.h"
 #include "nsStyleContext.h"
+#include "nsTArrayForwardDeclare.h"
 
 class nsBaseContentList;
 class nsIFrame;
-template <class T, class A> class nsTArray;
 
 /**
  * Any source for anonymous content can implement this interface to provide it.
  * HTML frames like nsFileControlFrame currently use this.
  *
  * @see nsCSSFrameConstructor
  */
 class nsIAnonymousContentCreator
--- a/layout/style/nsCSSStyleSheet.h
+++ b/layout/style/nsCSSStyleSheet.h
@@ -26,17 +26,16 @@
 class nsXMLNameSpaceMap;
 class nsCSSRuleProcessor;
 class nsIPrincipal;
 class nsIURI;
 class nsMediaList;
 class nsMediaQueryResultCacheKey;
 class nsCSSStyleSheet;
 class nsPresContext;
-template<class E, class A> class nsTArray;
 
 namespace mozilla {
 namespace css {
 class Rule;
 class GroupRule;
 class ImportRule;
 }
 }
--- a/modules/libpref/public/nsIPrefService.idl
+++ b/modules/libpref/public/nsIPrefService.idl
@@ -3,21 +3,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIPrefBranch.idl"
 
 %{C++
 struct PrefTuple;
-template<class E, class A> class nsTArray;
-struct nsTArrayInfallibleAllocator;
+#include "nsTArrayForwardDeclare.h"
 %}
 
-[ptr] native nsPreferencesArrayPtr(nsTArray<PrefTuple, nsTArrayInfallibleAllocator>);
+[ptr] native nsPreferencesArrayPtr(nsTArray<PrefTuple>);
 [ptr] native nsPreferencePtr(PrefTuple);
 [ptr] native nsPreferencePtrConst(const PrefTuple);
 
 interface nsIFile;
 
 /**
  * The nsIPrefService interface is the main entry point into the back end
  * preferences management library. The preference service is directly
--- a/xpcom/glue/Makefile.in
+++ b/xpcom/glue/Makefile.in
@@ -64,16 +64,17 @@ SDK_HEADERS = \
 		nsMemory.h \
 		nsQuickSort.h \
 		nsRefPtrHashtable.h \
 		nsServiceManagerUtils.h \
 		nsStringAPI.h \
 		nsStringGlue.h \
 		nsTArray.h \
 		nsTArray-inl.h \
+		nsTArrayForwardDeclare.h \
 		nsTHashtable.h \
 		nsTObserverArray.h \
 		nsTWeakRef.h \
 		nsTextFormatter.h \
 		nsTraceRefcnt.h \
 		nsVersionComparator.h \
 		nsVoidArray.h \
 		nsWeakReference.h \
--- a/xpcom/glue/nsTArray-inl.h
+++ b/xpcom/glue/nsTArray-inl.h
@@ -365,17 +365,17 @@ nsTArray_base<Alloc>::SwapArrayElements(
     largerElements = Hdr() + 1;
   }
 
   // Allocate temporary storage for the smaller of the two arrays.  We want to
   // allocate this space on the stack, if it's not too large.  Sounds like a
   // job for AutoTArray!  (One of the two arrays we're swapping is using an
   // auto buffer, so we're likely not allocating a lot of space here.  But one
   // could, in theory, allocate a huge AutoTArray on the heap.)
-  nsAutoTArray<uint8_t, 64, Alloc> temp;
+  nsAutoArrayBase<nsTArray_Impl<uint8_t, Alloc>, 64> temp;
   if (!temp.SetCapacity(smallerLength * elemSize)) {
     return false;
   }
 
   memcpy(temp.Elements(), smallerElements, smallerLength * elemSize);
   memcpy(smallerElements, largerElements, largerLength * elemSize);
   memcpy(largerElements, temp.Elements(), smallerLength * elemSize);
 
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -2,41 +2,85 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsTArray_h__
 #define nsTArray_h__
 
+#include "nsTArrayForwardDeclare.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Util.h"
 
 #include <string.h>
 
 #include "nsCycleCollectionNoteChild.h"
 #include "nsAlgorithm.h"
 #include "nscore.h"
 #include "nsQuickSort.h"
 #include "nsDebug.h"
 #include "nsTraceRefcnt.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.
+// nsTArray is a resizable array class, like std::vector.
+//
+// Unlike std::vector, which follows C++'s construction/destruction rules,
+// nsTArray assumes that your "T" can be memmoved()'ed safely.
+//
+// The public classes defined in this header are
+//
+//   nsTArray<T>,
+//   FallibleTArray<T>,
+//   nsAutoTArray<T, N>, and
+//   AutoFallibleTArray<T, N>.
+//
+// nsTArray and nsAutoTArray are infallible; if one tries to make an allocation
+// which fails, it crashes the program.  In contrast, FallibleTArray and
+// AutoFallibleTArray are fallible; if you use one of these classes, you must
+// check the return values of methods such as Append() which may allocate.  If
+// in doubt, choose an infallible type.
+//
+// InfallibleTArray and AutoInfallibleTArray are aliases for nsTArray and
+// nsAutoTArray.
 //
-// Don't use nsTArray if your "T" can't be memmove()d correctly.
+// If you just want to declare the nsTArray types (e.g., if you're in a header
+// file and don't need the full nsTArray definitions) consider including
+// nsTArrayForwardDeclare.h instead of nsTArray.h.
+//
+// The template parameter (i.e., T in nsTArray<T>) specifies the type of the
+// elements and has the following requirements:
+//
+//   T MUST be safely memmove()'able.
+//   T MUST define a copy-constructor.
+//   T MAY define operator< for sorting.
+//   T MAY define operator== for searching.
+//
+// For methods taking a Comparator instance, the Comparator must be a class
+// defining the following methods:
+//
+//   class Comparator {
+//     public:
+//       /** @return True if the elements are equals; false otherwise. */
+//       bool Equals(const elem_type& a, const Item& b) const;
+//
+//       /** @return True if (a < b); false otherwise. */
+//       bool LessThan(const elem_type& a, const Item& b) const;
+//   };
+//
+// The Equals method is used for searching, and the LessThan method is used for
+// searching and sorting.  The |Item| type above can be arbitrary, but must
+// match the Item type passed to the sort or search function.
 //
 
+
 //
-// nsTArray*Allocators must all use the same |free()|, to allow
-// swapping between fallible and infallible variants.  (NS_Free() and
-// moz_free() end up calling the same underlying free()).
+// nsTArray*Allocators must all use the same |free()|, to allow swap()'ing
+// between fallible and infallible variants.
 //
 
 #if defined(MOZALLOC_HAVE_XMALLOC)
 #include "mozilla/mozalloc_abort.h"
 
 struct nsTArrayFallibleAllocator
 {
   static void* Malloc(size_t size) {
@@ -401,62 +445,37 @@ public:
     return a < b;
   }
 };
 
 template <class E> class InfallibleTArray;
 template <class E> class FallibleTArray;
 
 //
-// The templatized array class that dynamically resizes its storage as
-// elements are added.  This class is designed to behave a bit like
-// std::vector, though note that unlike std::vector, nsTArray doesn't
-// follow C++ construction/destruction rules.
-//
-// The template parameter specifies the type of the elements (elem_type), and
-// has the following requirements:
+// nsTArray_Impl contains most of the guts supporting nsTArray, FallibleTArray,
+// nsAutoTArray, and AutoFallibleTArray.
 //
-//   elem_type MUST define a copy-constructor.
-//   elem_type MAY define operator< for sorting.
-//   elem_type MAY define operator== for searching.
-//
-// For methods taking a Comparator instance, the Comparator must be a class
-// defining the following methods:
-//
-//   class Comparator {
-//     public:
-//       /** @return True if the elements are equals; false otherwise. */
-//       bool Equals(const elem_type& a, const Item& b) const;
+// The only situation in which you might need to use nsTArray_Impl in your code
+// is if you're writing code which mutates a TArray which may or may not be
+// infallible.
 //
-//       /** @return True if (a < b); false otherwise. */
-//       bool LessThan(const elem_type& a, const Item& b) const;
-//   };
-//
-// The Equals method is used for searching, and the LessThan method is used
-// for sorting.  The |Item| type above can be arbitrary, but must match the
-// Item type passed to the sort or search function.
+// Code which merely reads from a TArray which may or may not be infallible can
+// simply cast the TArray to |const nsTArray&|; both fallible and infallible
+// TArrays can be cast to |const nsTArray&|.
 //
-// The Alloc template parameter can be used to choose between
-// "fallible" and "infallible" nsTArray (if available), defaulting to
-// fallible.  If the *fallible* allocator is used, the return value of
-// methods that might allocate needs to be checked; Append() is
-// one such method.  These return values don't need to be checked if
-// the *in*fallible allocator is chosen.  When in doubt, choose the
-// infallible allocator.
-//
-template<class E, class Alloc=nsTArrayInfallibleAllocator>
-class nsTArray : public nsTArray_base<Alloc>,
-                 public nsTArray_SafeElementAtHelper<E, nsTArray<E, Alloc> >
+template<class E, class Alloc>
+class nsTArray_Impl : public nsTArray_base<Alloc>,
+                      public nsTArray_SafeElementAtHelper<E, nsTArray_Impl<E, Alloc> >
 {
 public:
   typedef nsTArray_base<Alloc>           base_type;
   typedef typename base_type::size_type  size_type;
   typedef typename base_type::index_type index_type;
   typedef E                              elem_type;
-  typedef nsTArray<E, Alloc>             self_type;
+  typedef nsTArray_Impl<E, Alloc>        self_type;
   typedef nsTArrayElementTraits<E>       elem_traits;
   typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type;
 
   using safeelementat_helper_type::SafeElementAt;
   using base_type::EmptyHdr;
 
   // A special value that is used to indicate an invalid or unknown index
   // into the array.
@@ -465,66 +484,74 @@ public:
   };
 
   using base_type::Length;
 
   //
   // Finalization method
   //
 
-  ~nsTArray() { Clear(); }
+  ~nsTArray_Impl() { Clear(); }
 
   //
   // Initialization methods
   //
 
-  nsTArray() {}
+  nsTArray_Impl() {}
 
   // Initialize this array and pre-allocate some number of elements.
-  explicit nsTArray(size_type capacity) {
+  explicit nsTArray_Impl(size_type capacity) {
     SetCapacity(capacity);
   }
 
   // The array's copy-constructor performs a 'deep' copy of the given array.
   // @param other  The array object to copy.
-  explicit nsTArray(const self_type& other) {
-    AppendElements(other);
-  }
-
-  template<typename Allocator>
-  explicit nsTArray(const nsTArray<E, Allocator>& other) {
+  //
+  // It's very important that we declare this method as taking |const
+  // self_type&| as opposed to taking |const nsTArray_Impl<E, OtherAlloc>| for
+  // an arbitrary OtherAlloc.
+  //
+  // If we don't declare a constructor taking |const self_type&|, C++ generates
+  // a copy-constructor for this class which merely copies the object's
+  // members, which is obviously wrong.
+  //
+  // You can pass an nsTArray_Impl<E, OtherAlloc> to this method because
+  // nsTArray_Impl<E, X> can be cast to const nsTArray_Impl<E, Y>&.  So the
+  // effect on the API is the same as if we'd declared this method as taking
+  // |const nsTArray_Impl<E, OtherAlloc>&|.
+  explicit nsTArray_Impl(const self_type& other) {
     AppendElements(other);
   }
 
   // Allow converting to a const array with a different kind of allocator,
   // Since the allocator doesn't matter for const arrays
   template<typename Allocator>
-  operator const nsTArray<E, Allocator>&() const {
-    return *reinterpret_cast<const nsTArray<E, Allocator>*>(this);
+  operator const nsTArray_Impl<E, Allocator>&() const {
+    return *reinterpret_cast<const nsTArray_Impl<E, Allocator>*>(this);
   }
   // And we have to do this for our subclasses too
-  operator const InfallibleTArray<E>&() const {
+  operator const nsTArray<E>&() const {
     return *reinterpret_cast<const InfallibleTArray<E>*>(this);
   }
   operator const FallibleTArray<E>&() const {
     return *reinterpret_cast<const FallibleTArray<E>*>(this);
   }
 
   // The array's assignment operator performs a 'deep' copy of the given
   // array.  It is optimized to reuse existing storage if possible.
   // @param other  The array object to copy.
-  nsTArray& operator=(const self_type& other) {
+  self_type& operator=(const self_type& other) {
     ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
     return *this;
   }
 
   // Return true if this array has the same length and the same
   // elements as |other|.
   template<typename Allocator>
-  bool operator==(const nsTArray<E, Allocator>& other) const {
+  bool operator==(const nsTArray_Impl<E, Allocator>& other) const {
     size_type len = Length();
     if (len != other.Length())
       return false;
 
     // XXX std::equal would be as fast or faster here
     for (index_type i = 0; i < len; ++i)
       if (!(operator[](i) == other[i]))
         return false;
@@ -534,30 +561,30 @@ public:
 
   // Return true if this array does not have the same length and the same
   // elements as |other|.
   bool operator!=(const self_type& other) const {
     return !operator==(other);
   }
 
   template<typename Allocator>
-  nsTArray& operator=(const nsTArray<E, Allocator>& other) {
+  self_type& operator=(const nsTArray_Impl<E, Allocator>& other) {
     ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
     return *this;
   }
 
-  // @return The amount of memory used by this nsTArray, excluding
+  // @return The amount of memory used by this nsTArray_Impl, excluding
   // sizeof(*this).
   size_t SizeOfExcludingThis(nsMallocSizeOfFun mallocSizeOf) const {
     if (this->UsesAutoArrayBuffer() || Hdr() == EmptyHdr())
       return 0;
     return mallocSizeOf(this->Hdr());
   }
 
-  // @return The amount of memory used by this nsTArray, including
+  // @return The amount of memory used by this nsTArray_Impl, including
   // sizeof(*this).
   size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf) const {
     return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
   }
 
   //
   // Accessor methods
   //
@@ -805,18 +832,18 @@ public:
   // A variation on the ReplaceElementsAt method defined above.
   template<class Item>
   elem_type *InsertElementsAt(index_type index, const Item* array,
                               size_type arrayLen) {
     return ReplaceElementsAt(index, 0, array, arrayLen);
   }
 
   // A variation on the ReplaceElementsAt method defined above.
-  template<class Item>
-  elem_type *InsertElementsAt(index_type index, const nsTArray<Item>& array) {
+  template<class Item, class Allocator>
+  elem_type *InsertElementsAt(index_type index, const nsTArray_Impl<Item, Allocator>& array) {
     return ReplaceElementsAt(index, 0, array.Elements(), array.Length());
   }
 
   // A variation on the ReplaceElementsAt method defined above.
   template<class Item>
   elem_type *InsertElementAt(index_type index, const Item& item) {
     return ReplaceElementsAt(index, 0, &item, 1);
   }
@@ -926,17 +953,17 @@ public:
     index_type len = Length();
     AssignRange(len, arrayLen, array);
     this->IncrementLength(arrayLen);
     return Elements() + len;
   }
 
   // A variation on the AppendElements method defined above.
   template<class Item, class Allocator>
-  elem_type *AppendElements(const nsTArray<Item, Allocator>& array) {
+  elem_type *AppendElements(const nsTArray_Impl<Item, Allocator>& array) {
     return AppendElements(array.Elements(), array.Length());
   }
 
   // A variation on the AppendElements method defined above.
   template<class Item>
   elem_type *AppendElement(const Item& item) {
     return AppendElements(&item, 1);
   }
@@ -962,17 +989,17 @@ public:
   elem_type *AppendElement() {
     return AppendElements(1);
   }
 
   // Move all elements from another array to the end of this array without 
   // calling copy constructors or destructors.
   // @return A pointer to the newly appended elements, or null on OOM.
   template<class Item, class Allocator>
-  elem_type *MoveElementsFrom(nsTArray<Item, Allocator>& array) {
+  elem_type *MoveElementsFrom(nsTArray_Impl<Item, Allocator>& array) {
     MOZ_ASSERT(&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 nullptr;
     memcpy(Elements() + len, array.Elements(), otherLen * sizeof(elem_type));
     this->IncrementLength(otherLen);      
     array.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
@@ -1042,17 +1069,17 @@ public:
   template<class Item>
   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) {
+  bool SwapElements(nsTArray_Impl<E, Allocator>& other) {
     return this->SwapArrayElements(other, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
   }
 
   //
   // Allocation
   //
 
   // This method may increase the capacity of this array object by the
@@ -1158,17 +1185,17 @@ public:
   }
 
   //
   // Sorting
   //
  
   // This function is meant to be used with the NS_QuickSort function.  It
   // maps the callback API expected by NS_QuickSort to the Comparator API
-  // used by nsTArray.  See nsTArray::Sort.
+  // used by nsTArray_Impl.  See nsTArray_Impl::Sort.
   template<class Comparator>
   static int Compare(const void* e1, const void* e2, void *data) {
     const Comparator* c = reinterpret_cast<const Comparator*>(data);
     const elem_type* a = static_cast<const elem_type*>(e1);
     const elem_type* b = static_cast<const elem_type*>(e2);
     return c->LessThan(*a, *b) ? -1 : (c->Equals(*a, *b) ? 0 : 1);
   }
 
@@ -1312,115 +1339,93 @@ protected:
       elem[parent_index] = elem[index];
     }
     elem[index] = item;
   }
 };
 
 template <typename E, typename Alloc>
 inline void
-ImplCycleCollectionUnlink(nsTArray<E, Alloc>& aField)
+ImplCycleCollectionUnlink(nsTArray_Impl<E, Alloc>& aField)
 {
   aField.Clear();
 }
 
 template <typename E, typename Alloc>
 inline void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            nsTArray<E, Alloc>& aField,
+                            nsTArray_Impl<E, Alloc>& aField,
                             const char* aName,
                             uint32_t aFlags = 0)
 {
   aFlags |= CycleCollectionEdgeNameArrayFlag;
   size_t length = aField.Length();
   for (size_t i = 0; i < length; ++i) {
     ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
   }
 }
 
 //
-// Convenience subtypes of nsTArray.
+// nsTArray is an infallible vector class.  See the comment at the top of this
+// file for more details.
 //
 template <class E>
-class FallibleTArray : public nsTArray<E, nsTArrayFallibleAllocator>
+class nsTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
 {
 public:
-  typedef nsTArray<E, nsTArrayFallibleAllocator>   base_type;
-  typedef typename base_type::size_type            size_type;
+  typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
+  typedef nsTArray<E>                                   self_type;
+  typedef typename base_type::size_type                 size_type;
+
+  nsTArray() {}
+  explicit nsTArray(size_type capacity) : base_type(capacity) {}
+  nsTArray(const nsTArray& other) : base_type(other) {}
+
+  template<class Allocator>
+  nsTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
+};
+
+//
+// FallibleTArray is a fallible vector class.
+//
+template <class E>
+class FallibleTArray : public nsTArray_Impl<E, nsTArrayFallibleAllocator>
+{
+public:
+  typedef nsTArray_Impl<E, nsTArrayFallibleAllocator>   base_type;
+  typedef FallibleTArray<E>                             self_type;
+  typedef typename base_type::size_type                 size_type;
 
   FallibleTArray() {}
   explicit FallibleTArray(size_type capacity) : base_type(capacity) {}
-  FallibleTArray(const FallibleTArray& other) : base_type(other) {}
+  FallibleTArray(const FallibleTArray<E>& other) : base_type(other) {}
+
+  template<class Allocator>
+  FallibleTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
 };
 
-template <typename E>
-inline void
-ImplCycleCollectionUnlink(FallibleTArray<E>& aField)
-{
-  aField.Clear();
-}
-
-template <typename E>
-inline void
-ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            FallibleTArray<E>& aField,
-                            const char* aName,
-                            uint32_t aFlags = 0)
-{
-  aFlags |= CycleCollectionEdgeNameArrayFlag;
-  size_t length = aField.Length();
-  for (size_t i = 0; i < length; ++i) {
-    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
-  }
-}
-
-
-#ifdef MOZALLOC_HAVE_XMALLOC
-template <class E>
-class InfallibleTArray : public nsTArray<E, nsTArrayInfallibleAllocator>
-{
-public:
-  typedef nsTArray<E, nsTArrayInfallibleAllocator> base_type;
-  typedef typename base_type::size_type            size_type;
- 
-  InfallibleTArray() {}
-  explicit InfallibleTArray(size_type capacity) : base_type(capacity) {}
-  InfallibleTArray(const InfallibleTArray& other) : base_type(other) {}
-};
-
-template <typename E>
-inline void ImplCycleCollectionUnlink(InfallibleTArray<E>& aField)
-{
-  aField.Clear();
-}
-
-template <typename E>
-inline void
-ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            InfallibleTArray<E>& aField,
-                            const char* aName,
-                            uint32_t aFlags = 0)
-{
-  aFlags |= CycleCollectionEdgeNameArrayFlag;
-  size_t length = aField.Length();
-  for (size_t i = 0; i < length; ++i) {
-    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
-  }
-}
-
-#endif
-
+//
+// nsAutoArrayBase is a base class for AutoFallibleTArray and nsAutoTArray.
+// You shouldn't use this class directly.
+//
 template <class TArrayBase, uint32_t N>
 class nsAutoArrayBase : public TArrayBase
 {
 public:
+  typedef nsAutoArrayBase<TArrayBase, N> self_type;
   typedef TArrayBase base_type;
   typedef typename base_type::Header Header;
   typedef typename base_type::elem_type elem_type;
 
+  template<typename Allocator>
+  self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& other) {
+    base_type::operator=(other);
+    return *this;
+  }
+
 protected:
   nsAutoArrayBase() {
     Init();
   }
 
   // We need this constructor because nsAutoTArray and friends all have
   // implicit copy-constructors.  If we don't have this method, those
   // copy-constructors will call nsAutoArrayBase's implicit copy-constructor,
@@ -1459,28 +1464,64 @@ private:
   union {
     char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)];
     // Do the max operation inline to ensure that it is a compile-time constant.
     mozilla::AlignedElem<(MOZ_ALIGNOF(Header) > MOZ_ALIGNOF(elem_type))
                          ? MOZ_ALIGNOF(Header) : MOZ_ALIGNOF(elem_type)> mAlign;
   };
 };
 
-template<class E, uint32_t N, class Alloc=nsTArrayInfallibleAllocator>
-class nsAutoTArray : public nsAutoArrayBase<nsTArray<E, Alloc>, N>
+//
+// nsAutoTArray<E, N> is an infallible vector class with N elements of inline
+// storage.  If you try to store more than N elements inside an
+// nsAutoTArray<E, N>, we'll call malloc() and store them all on the heap.
+//
+// Note that you can cast an nsAutoTArray<E, N> to
+// |const AutoFallibleTArray<E, N>&|.
+//
+template<class E, uint32_t N>
+class nsAutoTArray : public nsAutoArrayBase<nsTArray<E>, N>
 {
-  typedef nsAutoArrayBase<nsTArray<E, Alloc>, N> Base;
+  typedef nsAutoTArray<E, N> self_type;
+  typedef nsAutoArrayBase<nsTArray<E>, N> Base;
 
 public:
   nsAutoTArray() {}
 
   template<typename Allocator>
-  nsAutoTArray(const nsTArray<E, Allocator>& other) {
+  nsAutoTArray(const nsTArray_Impl<E, Allocator>& other) {
     Base::AppendElements(other);
   }
+
+  operator const AutoFallibleTArray<E, N>&() const {
+    return *reinterpret_cast<const AutoFallibleTArray<E, N>*>(this);
+  }
+};
+
+//
+// AutoFallibleTArray<E, N> is a fallible vector class with N elements of
+// inline storage.
+//
+template<class E, uint32_t N>
+class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
+{
+  typedef AutoFallibleTArray<E, N> self_type;
+  typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
+
+public:
+  AutoFallibleTArray() {}
+
+  template<typename Allocator>
+  AutoFallibleTArray(const nsTArray_Impl<E, Allocator>& other) {
+    Base::AppendElements(other);
+  }
+
+  operator const nsAutoTArray<E, N>&() const {
+    return *reinterpret_cast<const nsAutoTArray<E, N>*>(this);
+  }
 };
 
 // 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<uint32_t, 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
@@ -1491,70 +1532,12 @@ public:
 // 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.
 
 MOZ_STATIC_ASSERT(sizeof(nsAutoTArray<uint32_t, 2>) ==
                   sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(uint32_t) * 2,
                   "nsAutoTArray shouldn't contain any extra padding, "
                   "see the comment");
 
-template<class E, uint32_t N>
-class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
-{
-  typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
-
-public:
-  AutoFallibleTArray() {}
-
-  template<typename Allocator>
-  AutoFallibleTArray(const nsTArray<E, Allocator>& other) {
-    Base::AppendElements(other);
-  }
-};
-
-#if defined(MOZALLOC_HAVE_XMALLOC)
-template<class E, uint32_t N>
-class AutoInfallibleTArray : public nsAutoArrayBase<InfallibleTArray<E>, N>
-{
-  typedef nsAutoArrayBase<InfallibleTArray<E>, N> Base;
-
-public:
-  AutoInfallibleTArray() {}
-
-  template<typename Allocator>
-  AutoInfallibleTArray(const nsTArray<E, Allocator>& other) {
-    Base::AppendElements(other);
-  }
-};
-#endif
-
-// specializations for N = 0. this makes the inheritance model easier for
-// templated users of nsAutoTArray.
-template<class E>
-class nsAutoTArray<E, 0, nsTArrayInfallibleAllocator> :
-  public nsAutoArrayBase< nsTArray<E, nsTArrayInfallibleAllocator>, 0>
-{
-public:
-  nsAutoTArray() {}
-};
-
-template<class E>
-class AutoFallibleTArray<E, 0> :
-  public nsAutoArrayBase< FallibleTArray<E>, 0>
-{
-public:
-  AutoFallibleTArray() {}
-};
-
-#if defined(MOZALLOC_HAVE_XMALLOC)
-template<class E>
-class AutoInfallibleTArray<E, 0> :
-  public nsAutoArrayBase< InfallibleTArray<E>, 0>
-{
-public:
-  AutoInfallibleTArray() {}
-};
-#endif
- 
-// Definitions of nsTArray methods
+// Definitions of nsTArray_Impl methods
 #include "nsTArray-inl.h"
 
 #endif  // nsTArray_h__
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/nsTArrayForwardDeclare.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsTArrayForwardDeclare_h__
+#define nsTArrayForwardDeclare_h__
+
+//
+// This simple header file contains forward declarations for the TArray family
+// of classes.
+//
+// Including this header is preferable to writing
+//
+//   template<class E> class nsTArray;
+//
+// yourself, since this header gives us flexibility to e.g. change the default
+// template parameters.
+//
+
+#include "mozilla/StandardInteger.h"
+
+template<class E>
+class nsTArray;
+
+template<class E>
+class FallibleTArray;
+
+template<class E, uint32_t N>
+class nsAutoTArray;
+
+template<class E, uint32_t N>
+class AutoFallibleTArray;
+
+#define InfallibleTArray nsTArray
+#define AutoInfallibleTArray nsAutoTArray
+
+#endif