comarray.patch
author Benjamin Smedberg <benjamin@smedbergs.us>
Sat, 26 Jul 2008 22:49:39 -0400
changeset 167 a4da40849f5436e629c5732f4368c6c48189637f
parent 162 3ae1ca70680d55840cbf5a60088ebaebfe2bddc5
permissions -rw-r--r--
State as of now

* * *

diff --git a/browser/components/migration/src/nsPhoenixProfileMigrator.h b/browser/components/migration/src/nsPhoenixProfileMigrator.h
--- a/browser/components/migration/src/nsPhoenixProfileMigrator.h
+++ b/browser/components/migration/src/nsPhoenixProfileMigrator.h
@@ -48,7 +48,6 @@ class nsIFile;
 class nsIFile;
 class nsIPrefBranch;
 class nsIPrefService;
-class nsVoidArray;
 
 class nsPhoenixProfileMigrator : public nsNetscapeProfileMigratorBase, 
                                  public nsIBrowserProfileMigrator
diff --git a/browser/components/migration/src/nsSeamonkeyProfileMigrator.h b/browser/components/migration/src/nsSeamonkeyProfileMigrator.h
--- a/browser/components/migration/src/nsSeamonkeyProfileMigrator.h
+++ b/browser/components/migration/src/nsSeamonkeyProfileMigrator.h
@@ -44,11 +44,11 @@
 #include "nsISupportsArray.h"
 #include "nsNetscapeProfileMigratorBase.h"
 #include "nsStringAPI.h"
+#include "nsVoidArray.h"
 
 class nsIFile;
 class nsIPrefBranch;
 class nsIPrefService;
-class nsVoidArray;
 
 class nsSeamonkeyProfileMigrator : public nsNetscapeProfileMigratorBase, 
                                    public nsIBrowserProfileMigrator
diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -96,7 +96,6 @@ class nsIRunnable;
 class nsIRunnable;
 template<class E> class nsCOMArray;
 class nsIPref;
-class nsVoidArray;
 struct JSRuntime;
 class nsICaseConversion;
 class nsIUGenCategory;
diff --git a/content/base/public/nsIContent.h b/content/base/public/nsIContent.h
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -48,7 +48,6 @@ class nsIAtom;
 class nsIAtom;
 class nsIDocument;
 class nsPresContext;
-class nsVoidArray;
 class nsIDOMEvent;
 class nsIContent;
 class nsIEventListenerManager;
diff --git a/content/base/public/nsINode.h b/content/base/public/nsINode.h
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -55,7 +55,6 @@ class nsEventChainPostVisitor;
 class nsEventChainPostVisitor;
 class nsIEventListenerManager;
 class nsIPrincipal;
-class nsVoidArray;
 class nsIMutationObserver;
 class nsChildContentList;
 class nsNodeWeakReference;
diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -72,7 +72,6 @@ class nsDOMCSSDeclaration;
 class nsDOMCSSDeclaration;
 class nsIDOMCSSStyleDeclaration;
 class nsIURI;
-class nsVoidArray;
 class nsINodeInfo;
 class nsIControllers;
 class nsIDOMNSFeatureFactory;
diff --git a/content/base/src/nsRange.h b/content/base/src/nsRange.h
--- a/content/base/src/nsRange.h
+++ b/content/base/src/nsRange.h
@@ -52,8 +52,6 @@
 #include "nsIDOMNode.h"
 #include "prmon.h"
 #include "nsStubMutationObserver.h"
-
-class nsVoidArray;
 
 // -------------------------------------------------------------------------------
 
diff --git a/editor/libeditor/html/nsHTMLEditRules.h b/editor/libeditor/html/nsHTMLEditRules.h
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -49,7 +49,6 @@
 #include "TypeInState.h"
 #include "nsReadableUtils.h"
 
-class nsVoidArray;
 class nsIDOMElement;
 class nsIEditor;
 class nsHTMLEditor;
diff --git a/editor/txmgr/src/nsTransactionManager.h b/editor/txmgr/src/nsTransactionManager.h
--- a/editor/txmgr/src/nsTransactionManager.h
+++ b/editor/txmgr/src/nsTransactionManager.h
@@ -41,13 +41,13 @@
 #include "prmon.h"
 #include "nsWeakReference.h"
 #include "nsITransactionManager.h"
+#include "nsVoidArray.h"
 
 class nsITransaction;
 class nsITransactionListener;
 class nsTransactionItem;
 class nsTransactionStack;
 class nsTransactionRedoStack;
-class nsVoidArray;
 
 /** implementation of a transaction manager object.
  *
diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -61,7 +61,6 @@ struct nsStyleContent;
 struct nsStyleContent;
 struct nsStyleDisplay;
 class nsIPresShell;
-class nsVoidArray;
 class nsFrameManager;
 class nsIDOMHTMLSelectElement;
 class nsPresContext;
diff --git a/layout/forms/nsIComboboxControlFrame.h b/layout/forms/nsIComboboxControlFrame.h
--- a/layout/forms/nsIComboboxControlFrame.h
+++ b/layout/forms/nsIComboboxControlFrame.h
@@ -44,7 +44,6 @@ class nsPresContext;
 class nsPresContext;
 class nsString;
 class nsIContent;
-class nsVoidArray;
 class nsCSSFrameConstructor;
 
 
diff --git a/layout/forms/nsListControlFrame.h b/layout/forms/nsListControlFrame.h
--- a/layout/forms/nsListControlFrame.h
+++ b/layout/forms/nsListControlFrame.h
@@ -63,9 +63,6 @@ class nsIDOMHTMLOptionElement;
 class nsIDOMHTMLOptionElement;
 class nsIComboboxControlFrame;
 class nsPresContext;
-class nsVoidArray;
-
-class nsVoidArray;
 class nsListEventListener;
 
 /**
diff --git a/layout/tables/nsTableColFrame.h b/layout/tables/nsTableColFrame.h
--- a/layout/tables/nsTableColFrame.h
+++ b/layout/tables/nsTableColFrame.h
@@ -41,7 +41,6 @@
 #include "nsContainerFrame.h"
 #include "nsTablePainter.h"
 
-class nsVoidArray;
 class nsTableCellFrame;
 
 enum nsTableColType {
diff --git a/netwerk/cookie/src/nsCookieService.h b/netwerk/cookie/src/nsCookieService.h
--- a/netwerk/cookie/src/nsCookieService.h
+++ b/netwerk/cookie/src/nsCookieService.h
@@ -54,6 +54,7 @@ struct nsListIter;
 struct nsListIter;
 struct nsEnumerationData;
 
+class nsIPrefBranch;
 class nsICookiePermission;
 class nsIEffectiveTLDService;
 class nsIPrefBranch;
diff --git a/rdf/datasource/public/nsIRDFFileSystem.h b/rdf/datasource/public/nsIRDFFileSystem.h
--- a/rdf/datasource/public/nsIRDFFileSystem.h
+++ b/rdf/datasource/public/nsIRDFFileSystem.h
@@ -42,9 +42,6 @@
 #include "nsISupports.h"
 #include "nsIRDFNode.h"
 
-class nsVoidArray;
-
-
 #define NS_IRDFFILESYSTEMDATAOURCE_IID \
 { 0x1222e6f0, 0xa5e3, 0x11d2, { 0x8b, 0x7c, 0x00, 0x80, 0x5f, 0x8a, 0x7d, 0xb5 } }
 
diff --git a/widget/src/windows/nsDataObj.h b/widget/src/windows/nsDataObj.h
--- a/widget/src/windows/nsDataObj.h
+++ b/widget/src/windows/nsDataObj.h
@@ -128,7 +128,6 @@ typedef struct _FILEGROUPDESCRIPTORW {
 # endif /*__W32API_MAJOR_VERSION*/
 #endif /*__MINGW32__*/
 
-class nsVoidArray;
 class CEnumFormatEtc;
 class nsITransferable;
 
diff --git a/widget/src/xpwidgets/nsTransferable.h b/widget/src/xpwidgets/nsTransferable.h
--- a/widget/src/xpwidgets/nsTransferable.h
+++ b/widget/src/xpwidgets/nsTransferable.h
@@ -41,12 +41,11 @@
 #include "nsIFormatConverter.h"
 #include "nsITransferable.h"
 #include "nsCOMPtr.h"
+#include "nsVoidArray.h"
 
 
-class nsVoidArray;
 class nsString;
 class nsDataObj;
-class nsVoidArray;
 
 
 /**
diff --git a/xpcom/base/Makefile.in b/xpcom/base/Makefile.in
--- a/xpcom/base/Makefile.in
+++ b/xpcom/base/Makefile.in
@@ -53,7 +53,6 @@ REQUIRES	= string \
 		  $(NULL)
 
 CPPSRCS		= \
-		nsAllocator.cpp \
 		nsVersionComparatorImpl.cpp \
 		nsConsoleMessage.cpp \
 		nsConsoleService.cpp \
diff --git a/xpcom/base/nsAllocator.cpp b/xpcom/base/nsAllocator.cpp
deleted file mode 100644
--- a/xpcom/base/nsAllocator.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** 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 mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Pierre Phaneuf <pp@ludusdesign.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of 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 ***** */
-
-////////////////////////////////////////////////////////////////////////////////
-// obsolete
-////////////////////////////////////////////////////////////////////////////////
diff --git a/xpcom/base/nsAllocator.h b/xpcom/base/nsAllocator.h
deleted file mode 100644
--- a/xpcom/base/nsAllocator.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** 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 mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of 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 ***** */
-
-////////////////////////////////////////////////////////////////////////////////
-// obsolete
-////////////////////////////////////////////////////////////////////////////////
-
-#ifndef nsAllocator_h__
-#define nsAllocator_h__
-
-#include "nsIAllocator.h"
-#include "prmem.h"
-#include "nsAgg.h"
-#include "nsIFactory.h"
-
-#endif // nsAllocator_h__
diff --git a/xpcom/glue/Makefile.in b/xpcom/glue/Makefile.in
--- a/xpcom/glue/Makefile.in
+++ b/xpcom/glue/Makefile.in
@@ -74,6 +74,7 @@ CPPSRCS		= \
 
 SDK_HEADERS = \
 		pldhash.h \
+		nsAllocator.h \
 		nsArrayEnumerator.h \
 		nsArrayUtils.h \
 		nsAutoLock.h \
diff --git a/xpcom/glue/nsAllocator.cpp b/xpcom/glue/nsAllocator.cpp
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/nsAllocator.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** 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 mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Pierre Phaneuf <pp@ludusdesign.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 "nsAllocator.h"
+#include "nsDebug.h"
+
+void*
+GCAllocator::Realloc(void *object, size_t oldsize, size_t newsize)
+{
+    NS_ASSERTION(object, "Calling Realloc without an original object.");
+
+    if (oldsize > newsize)
+        return object;
+
+    void *newobject = Alloc(newsize);
+    if (!newobject)
+        return NULL;
+
+    memset(reinterpret_cast<char*>(newobject) + oldsize, 0, newsize - oldsize);
+    memcpy(newobject, object, oldsize);
+    return newobject;
+}
diff --git a/xpcom/glue/nsAllocator.h b/xpcom/glue/nsAllocator.h
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/nsAllocator.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** 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 mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+////////////////////////////////////////////////////////////////////////////////
+// obsolete
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef nsAllocator_h__
+#define nsAllocator_h__
+
+#include <stdlib.h>
+
+#include "nsXPCOM.h"
+#include "MMgc.h"
+
+/**
+ * The following classes are all static and follow the same pattern:
+ *
+ * void* Alloc(size_t size);
+ * void* Realloc(void *object, size_t oldsize, size_t newsize);
+ * void Free(void *object);
+ */
+
+/**
+ * Allocates using the standard-library malloc/free allocators.
+ */
+class CAllocator
+{
+public:
+    static void* Alloc(size_t size)
+    {
+        return malloc(size);
+    }
+
+    static void* Realloc(void *object, size_t oldsize, size_t newsize)
+    {
+        return realloc(object, newsize);
+    }
+
+    static void Free(void *object)
+    {
+        free(object);
+    }
+};
+
+/**
+ * Allocates using the global GC
+ */
+class GCAllocator
+{
+public:
+    static void* Alloc(size_t size)
+    {
+        return NS_GetGC()->Alloc(size);
+    }
+
+    NS_COM_GLUE static void* Realloc(void *object, size_t oldsize, size_t newsize);
+
+    static void Free(void *object)
+    {
+        // Not allowed to call GC::Free during finalization...
+        // We'd really like to eagerly-free nsCOMArray buffers allocated from
+        // the stack... need to think about this
+    }
+};
+
+#endif // nsAllocator_h__
diff --git a/xpcom/glue/nsCOMArray.cpp b/xpcom/glue/nsCOMArray.cpp
--- a/xpcom/glue/nsCOMArray.cpp
+++ b/xpcom/glue/nsCOMArray.cpp
@@ -51,15 +51,6 @@ nsCOMArray_base::nsCOMArray_base(const n
     // make sure we do only one allocation
     mArray.SizeTo(aOther.Count());
     AppendObjects(aOther);
-}
-
-nsCOMArray_base::~nsCOMArray_base()
-{
-    PRInt32 count = Count(), i;
-    for (i = 0; i < count; ++i) {
-        nsISupports* obj = ObjectAt(i);
-        NS_IF_RELEASE(obj);
-    }                        
 }
 
 PRInt32
diff --git a/xpcom/glue/nsCOMArray.h b/xpcom/glue/nsCOMArray.h
--- a/xpcom/glue/nsCOMArray.h
+++ b/xpcom/glue/nsCOMArray.h
@@ -39,7 +39,7 @@
 #ifndef nsCOMArray_h__
 #define nsCOMArray_h__
 
-#include "nsVoidArray.h"
+#include "nsVoidArray.h" // for enumerator type declarations
 #include "nsISupports.h"
 
 // See below for the definition of nsCOMArray<T>
@@ -53,7 +53,6 @@ protected:
     nsCOMArray_base() {}
     nsCOMArray_base(PRInt32 aCount) : mArray(aCount) {}
     nsCOMArray_base(const nsCOMArray_base& other);
-    ~nsCOMArray_base();
 
     PRInt32 IndexOf(nsISupports* aObject) const {
         return mArray.IndexOf(aObject);
@@ -118,7 +117,7 @@ private:
 private:
     
     // the actual storage
-    nsVoidArray mArray;
+    nsVoidArrayBase<GCAllocator> mArray;
 
     // don't implement these, defaults will muck with refcounts!
     nsCOMArray_base& operator=(const nsCOMArray_base& other);
@@ -152,8 +151,6 @@ class nsCOMArray : public nsCOMArray_bas
     // only to be used by trusted classes who are going to pass us the
     // right type!
     nsCOMArray(const nsCOMArray<T>& aOther) : nsCOMArray_base(aOther) { }
-
-    ~nsCOMArray() {}
 
     // these do NOT refcount on the way out, for speed
     T* ObjectAt(PRInt32 aIndex) const {
diff --git a/xpcom/glue/nsVoidArray.cpp b/xpcom/glue/nsVoidArray.cpp
--- a/xpcom/glue/nsVoidArray.cpp
+++ b/xpcom/glue/nsVoidArray.cpp
@@ -42,674 +42,6 @@
 #include "prbit.h"
 #include "nsISupportsImpl.h" // for nsTraceRefcnt
 #include "nsCRTGlue.h"
-
-/**
- * Grow the array by at least this many elements at a time.
- */
-static const PRInt32 kMinGrowArrayBy = 8;
-static const PRInt32 kMaxGrowArrayBy = 1024;
-static const PRInt32 kAutoClearCompactSizeFactor = 4;
-
-/**
- * This is the threshold (in bytes) of the mImpl struct, past which
- * we'll force the array to grow geometrically
- */
-static const PRInt32 kLinearThreshold = 24 * sizeof(void *);
-
-/**
- * Compute the number of bytes requires for the mImpl struct that will
- * hold |n| elements.
- */
-#define SIZEOF_IMPL(n_) (sizeof(Impl) + sizeof(void *) * ((n_) - 1))
-
-
-/**
- * Compute the number of elements that an mImpl struct of |n| bytes
- * will hold.
- */
-#define CAPACITYOF_IMPL(n_) ((((n_) - sizeof(Impl)) / sizeof(void *)) + 1)
-
-#if DEBUG_VOIDARRAY
-#define MAXVOID 10
-
-class VoidStats {
-public:
-  VoidStats();
-  ~VoidStats();
-
-};
-
-static int sizesUsed; // number of the elements of the arrays used
-static int sizesAlloced[MAXVOID]; // sizes of the allocations.  sorted
-static int NumberOfSize[MAXVOID]; // number of this allocation size (1 per array)
-static int AllocedOfSize[MAXVOID]; // number of this allocation size (each size for array used)
-static int MaxAuto[MAXVOID];      // AutoArrays that maxed out at this size
-static int GrowInPlace[MAXVOID];  // arrays this size that grew in-place via realloc
-
-// these are per-allocation  
-static int MaxElements[2000];     // # of arrays that maxed out at each size.
-
-// statistics macros
-#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
-                                  { \
-                                    if (sizesAlloced[i] == (int)(size)) \
-                                    { ((x)[i])++; break; } \
-                                  } \
-                                  if (i >= sizesUsed && sizesUsed < MAXVOID) \
-                                  { sizesAlloced[sizesUsed] = (size); \
-                                    ((x)[sizesUsed++])++; break; \
-                                  } \
-                                } while (0)
-
-#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \
-                                    { \
-                                      if (sizesAlloced[i] == (int)(size)) \
-                                      { ((x)[i])--; break; } \
-                                    } \
-                                  } while (0)
-
-
-VoidStats::VoidStats()
-{
-  sizesUsed = 1;
-  sizesAlloced[0] = 0;
-}
-
-VoidStats::~VoidStats()
-{
-  int i;
-  for (i = 0; i < sizesUsed; i++)
-  {
-    printf("Size %d:\n",sizesAlloced[i]);
-    printf("\tNumber of VoidArrays this size (max):     %d\n",NumberOfSize[i]-MaxAuto[i]);
-    printf("\tNumber of AutoVoidArrays this size (max): %d\n",MaxAuto[i]);
-    printf("\tNumber of allocations this size (total):  %d\n",AllocedOfSize[i]);
-    printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]);
-  }
-  printf("Max Size of VoidArray:\n");
-  for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++)
-  {
-    if (MaxElements[i])
-      printf("\t%d: %d\n",i,MaxElements[i]);
-  }
-}
-
-// Just so constructor/destructor's get called
-VoidStats gVoidStats;
-#endif
-
-void
-nsVoidArray::SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount,
-                      PRBool aOwner, PRBool aHasAuto)
-{
-  // old mImpl has been realloced and so we don't free/delete it
-  NS_PRECONDITION(newImpl, "can't set size");
-  mImpl = newImpl;
-  mImpl->mCount = aCount;
-  mImpl->mBits = static_cast<PRUint32>(aSize & kArraySizeMask) |
-                 (aOwner ? kArrayOwnerMask : 0) |
-                 (aHasAuto ? kArrayHasAutoBufferMask : 0);
-}
-
-// This does all allocation/reallocation of the array.
-// It also will compact down to N - good for things that might grow a lot
-// at times,  but usually are smaller, like JS deferred GC releases.
-PRBool nsVoidArray::SizeTo(PRInt32 aSize)
-{
-  PRUint32 oldsize = GetArraySize();
-  PRBool isOwner = IsArrayOwner();
-  PRBool hasAuto = HasAutoBuffer();
-
-  if (aSize == (PRInt32) oldsize)
-    return PR_TRUE; // no change
-
-  if (aSize <= 0)
-  {
-    // free the array if allocated
-    if (mImpl)
-    {
-      if (isOwner)
-      {
-        free(reinterpret_cast<char *>(mImpl));
-        if (hasAuto) {
-          static_cast<nsAutoVoidArray*>(this)->ResetToAutoBuffer();
-        }
-        else {
-          mImpl = nsnull;
-        }
-      }
-      else
-      {
-        mImpl->mCount = 0; // nsAutoVoidArray
-      }
-    }
-    return PR_TRUE;
-  }
-
-  if (mImpl && isOwner)
-  {
-    // We currently own an array impl. Resize it appropriately.
-    if (aSize < mImpl->mCount)
-    {
-      // XXX Note: we could also just resize to mCount
-      return PR_TRUE;  // can't make it that small, ignore request
-    }
-
-    char* bytes = (char *) realloc(mImpl,SIZEOF_IMPL(aSize));
-    Impl* newImpl = reinterpret_cast<Impl*>(bytes);
-    if (!newImpl)
-      return PR_FALSE;
-
-#if DEBUG_VOIDARRAY
-    if (mImpl == newImpl)
-      ADD_TO_STATS(GrowInPlace,oldsize);
-    ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize));
-    if (aSize > mMaxSize)
-    {
-      ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize));
-      if (oldsize)
-        SUB_FROM_STATS(NumberOfSize,oldsize);
-      mMaxSize = aSize;
-      if (mIsAuto)
-      {
-        ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize));
-        SUB_FROM_STATS(MaxAuto,oldsize);
-      }
-    }
-#endif
-    SetArray(newImpl, aSize, newImpl->mCount, PR_TRUE, hasAuto);
-    return PR_TRUE;
-  }
-
-  if ((PRUint32) aSize < oldsize) {
-    // No point in allocating if it won't free the current Impl anyway.
-    return PR_TRUE;
-  }
-
-  // just allocate an array
-  // allocate the exact size requested
-  char* bytes = (char *) malloc(SIZEOF_IMPL(aSize));
-  Impl* newImpl = reinterpret_cast<Impl*>(bytes);
-  if (!newImpl)
-    return PR_FALSE;
-
-#if DEBUG_VOIDARRAY
-  ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize));
-  if (aSize > mMaxSize)
-  {
-    ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize));
-    if (oldsize && !mImpl)
-      SUB_FROM_STATS(NumberOfSize,oldsize);
-    mMaxSize = aSize;
-  }
-#endif
-  if (mImpl)
-  {
-#if DEBUG_VOIDARRAY
-    ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize));
-    SUB_FROM_STATS(MaxAuto,0);
-    SUB_FROM_STATS(NumberOfSize,0);
-    mIsAuto = PR_TRUE;
-#endif
-    // We must be growing an nsAutoVoidArray - copy since we didn't
-    // realloc.
-    memcpy(newImpl->mArray, mImpl->mArray,
-                  mImpl->mCount * sizeof(mImpl->mArray[0]));
-  }
-
-  SetArray(newImpl, aSize, mImpl ? mImpl->mCount : 0, PR_TRUE, hasAuto);
-  // no memset; handled later in ReplaceElementAt if needed
-  return PR_TRUE;
-}
-
-PRBool nsVoidArray::GrowArrayBy(PRInt32 aGrowBy)
-{
-  // We have to grow the array. Grow by kMinGrowArrayBy slots if we're
-  // smaller than kLinearThreshold bytes, or a power of two if we're
-  // larger.  This is much more efficient with most memory allocators,
-  // especially if it's very large, or of the allocator is binned.
-  if (aGrowBy < kMinGrowArrayBy)
-    aGrowBy = kMinGrowArrayBy;
-
-  PRUint32 newCapacity = GetArraySize() + aGrowBy;  // Minimum increase
-  PRUint32 newSize = SIZEOF_IMPL(newCapacity);
-
-  if (newSize >= (PRUint32) kLinearThreshold)
-  {
-    // newCount includes enough space for at least kMinGrowArrayBy new
-    // slots. Select the next power-of-two size in bytes above or
-    // equal to that.
-    // Also, limit the increase in size to about a VM page or two.
-    if (GetArraySize() >= kMaxGrowArrayBy)
-    {
-      newCapacity = GetArraySize() + PR_MAX(kMaxGrowArrayBy,aGrowBy);
-      newSize = SIZEOF_IMPL(newCapacity);
-    }
-    else
-    {
-      PR_CEILING_LOG2(newSize, newSize);
-      newCapacity = CAPACITYOF_IMPL(PR_BIT(newSize));
-    }
-  }
-  // frees old mImpl IF this succeeds
-  if (!SizeTo(newCapacity))
-    return PR_FALSE;
-
-  return PR_TRUE;
-}
-
-nsVoidArray::nsVoidArray()
-  : mImpl(nsnull)
-{
-  MOZ_COUNT_CTOR(nsVoidArray);
-#if DEBUG_VOIDARRAY
-  mMaxCount = 0;
-  mMaxSize = 0;
-  mIsAuto = PR_FALSE;
-  ADD_TO_STATS(NumberOfSize,0);
-  MaxElements[0]++;
-#endif
-}
-
-nsVoidArray::nsVoidArray(PRInt32 aCount)
-  : mImpl(nsnull)
-{
-  MOZ_COUNT_CTOR(nsVoidArray);
-#if DEBUG_VOIDARRAY
-  mMaxCount = 0;
-  mMaxSize = 0;
-  mIsAuto = PR_FALSE;
-  MaxElements[0]++;
-#endif
-  SizeTo(aCount);
-}
-
-nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other)
-{
-  PRInt32 otherCount = other.Count();
-  PRInt32 maxCount = GetArraySize();
-  if (otherCount)
-  {
-    if (otherCount > maxCount)
-    {
-      // frees old mImpl IF this succeeds
-      if (!GrowArrayBy(otherCount-maxCount))
-        return *this;      // XXX The allocation failed - don't do anything
-
-      memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
-      mImpl->mCount = otherCount;
-    }
-    else
-    {
-      // the old array can hold the new array
-      memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
-      mImpl->mCount = otherCount;
-      // if it shrank a lot, compact it anyways
-      if ((otherCount*2) < maxCount && maxCount > 100)
-      {
-        Compact();  // shrank by at least 50 entries
-      }
-    }
-#if DEBUG_VOIDARRAY
-     if (mImpl->mCount > mMaxCount &&
-         mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
-     {
-       MaxElements[mImpl->mCount]++;
-       MaxElements[mMaxCount]--;
-       mMaxCount = mImpl->mCount;
-     }
-#endif
-  }
-  else
-  {
-    // Why do we drop the buffer here when we don't in Clear()?
-    SizeTo(0);
-  }
-
-  return *this;
-}
-
-nsVoidArray::~nsVoidArray()
-{
-  MOZ_COUNT_DTOR(nsVoidArray);
-  if (mImpl && IsArrayOwner())
-    free(reinterpret_cast<char*>(mImpl));
-}
-
-PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const
-{
-  if (mImpl)
-  {
-    void** ap = mImpl->mArray;
-    void** end = ap + mImpl->mCount;
-    while (ap < end)
-    {
-      if (*ap == aPossibleElement)
-      {
-        return ap - mImpl->mArray;
-      }
-      ap++;
-    }
-  }
-  return -1;
-}
-
-PRBool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex)
-{
-  PRInt32 oldCount = Count();
-  NS_ASSERTION(aIndex >= 0,"InsertElementAt(negative index)");
-  if (PRUint32(aIndex) > PRUint32(oldCount))
-  {
-    // An invalid index causes the insertion to fail
-    // Invalid indexes are ones that add more than one entry to the
-    // array (i.e., they can append).
-    return PR_FALSE;
-  }
-
-  if (oldCount >= GetArraySize())
-  {
-    if (!GrowArrayBy(1))
-      return PR_FALSE;
-  }
-  // else the array is already large enough
-
-  PRInt32 slide = oldCount - aIndex;
-  if (0 != slide)
-  {
-    // Slide data over to make room for the insertion
-    memmove(mImpl->mArray + aIndex + 1, mImpl->mArray + aIndex,
-            slide * sizeof(mImpl->mArray[0]));
-  }
-
-  mImpl->mArray[aIndex] = aElement;
-  mImpl->mCount++;
-
-#if DEBUG_VOIDARRAY
-  if (mImpl->mCount > mMaxCount &&
-      mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
-  {
-    MaxElements[mImpl->mCount]++;
-    MaxElements[mMaxCount]--;
-    mMaxCount = mImpl->mCount;
-  }
-#endif
-
-  return PR_TRUE;
-}
-
-PRBool nsVoidArray::InsertElementsAt(const nsVoidArray& other, PRInt32 aIndex)
-{
-  PRInt32 oldCount = Count();
-  PRInt32 otherCount = other.Count();
-
-  NS_ASSERTION(aIndex >= 0,"InsertElementsAt(negative index)");
-  if (PRUint32(aIndex) > PRUint32(oldCount))
-  {
-    // An invalid index causes the insertion to fail
-    // Invalid indexes are ones that are more than one entry past the end of
-    // the array (i.e., they can append).
-    return PR_FALSE;
-  }
-
-  if (oldCount + otherCount > GetArraySize())
-  {
-    if (!GrowArrayBy(otherCount))
-      return PR_FALSE;;
-  }
-  // else the array is already large enough
-
-  PRInt32 slide = oldCount - aIndex;
-  if (0 != slide)
-  {
-    // Slide data over to make room for the insertion
-    memmove(mImpl->mArray + aIndex + otherCount, mImpl->mArray + aIndex,
-            slide * sizeof(mImpl->mArray[0]));
-  }
-
-  for (PRInt32 i = 0; i < otherCount; i++)
-  {
-    // copy all the elements (destroys aIndex)
-    mImpl->mArray[aIndex++] = other.mImpl->mArray[i];
-    mImpl->mCount++;
-  }
-
-#if DEBUG_VOIDARRAY
-  if (mImpl->mCount > mMaxCount &&
-      mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
-  {
-    MaxElements[mImpl->mCount]++;
-    MaxElements[mMaxCount]--;
-    mMaxCount = mImpl->mCount;
-  }
-#endif
-
-  return PR_TRUE;
-}
-
-PRBool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex)
-{
-  NS_ASSERTION(aIndex >= 0,"ReplaceElementAt(negative index)");
-  if (aIndex < 0)
-    return PR_FALSE;
-
-  // Unlike InsertElementAt, ReplaceElementAt can implicitly add more
-  // than just the one element to the array.
-  if (PRUint32(aIndex) >= PRUint32(GetArraySize()))
-  {
-    PRInt32 oldCount = Count();
-    PRInt32 requestedCount = aIndex + 1;
-    PRInt32 growDelta = requestedCount - oldCount;
-
-    // frees old mImpl IF this succeeds
-    if (!GrowArrayBy(growDelta))
-      return PR_FALSE;
-  }
-
-  mImpl->mArray[aIndex] = aElement;
-  if (aIndex >= mImpl->mCount)
-  {
-    // Make sure that any entries implicitly added to the array by this
-    // ReplaceElementAt are cleared to 0.  Some users of this assume that.
-    // This code means we don't have to memset when we allocate an array.
-    if (aIndex > mImpl->mCount) // note: not >=
-    {
-      // For example, if mCount is 2, and we do a ReplaceElementAt for
-      // element[5], then we need to set three entries ([2], [3], and [4])
-      // to 0.
-      memset(&mImpl->mArray[mImpl->mCount], 0,
-             (aIndex - mImpl->mCount) * sizeof(mImpl->mArray[0]));
-    }
-    
-     mImpl->mCount = aIndex + 1;
-
-#if DEBUG_VOIDARRAY
-     if (mImpl->mCount > mMaxCount &&
-         mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
-     {
-       MaxElements[mImpl->mCount]++;
-       MaxElements[mMaxCount]--;
-       mMaxCount = mImpl->mCount;
-     }
-#endif
-  }
-
-  return PR_TRUE;
-}
-
-// useful for doing LRU arrays
-PRBool nsVoidArray::MoveElement(PRInt32 aFrom, PRInt32 aTo)
-{
-  void *tempElement;
-
-  if (aTo == aFrom)
-    return PR_TRUE;
-
-  NS_ASSERTION(aTo >= 0 && aFrom >= 0,"MoveElement(negative index)");
-  if (aTo >= Count() || aFrom >= Count())
-  {
-    // can't extend the array when moving an element.  Also catches mImpl = null
-    return PR_FALSE;
-  }
-  tempElement = mImpl->mArray[aFrom];
-
-  if (aTo < aFrom)
-  {
-    // Moving one element closer to the head; the elements inbetween move down
-    memmove(mImpl->mArray + aTo + 1, mImpl->mArray + aTo,
-            (aFrom-aTo) * sizeof(mImpl->mArray[0]));
-    mImpl->mArray[aTo] = tempElement;
-  }
-  else // already handled aFrom == aTo
-  {
-    // Moving one element closer to the tail; the elements inbetween move up
-    memmove(mImpl->mArray + aFrom, mImpl->mArray + aFrom + 1,
-            (aTo-aFrom) * sizeof(mImpl->mArray[0]));
-    mImpl->mArray[aTo] = tempElement;
-  }
-
-  return PR_TRUE;
-}
-
-PRBool nsVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount)
-{
-  PRInt32 oldCount = Count();
-  NS_ASSERTION(aIndex >= 0,"RemoveElementsAt(negative index)");
-  if (PRUint32(aIndex) >= PRUint32(oldCount))
-  {
-    // An invalid index causes the replace to fail
-    return PR_FALSE;
-  }
-  // Limit to available entries starting at aIndex
-  if (aCount + aIndex > oldCount)
-    aCount = oldCount - aIndex;
-
-  // We don't need to move any elements if we're removing the
-  // last element in the array
-  if (aIndex < (oldCount - aCount))
-  {
-    memmove(mImpl->mArray + aIndex, mImpl->mArray + aIndex + aCount,
-            (oldCount - (aIndex + aCount)) * sizeof(mImpl->mArray[0]));
-  }
-
-  mImpl->mCount -= aCount;
-  return PR_TRUE;
-}
-
-PRBool nsVoidArray::RemoveElement(void* aElement)
-{
-  PRInt32 theIndex = IndexOf(aElement);
-  if (theIndex != -1)
-    return RemoveElementAt(theIndex);
-
-  return PR_FALSE;
-}
-
-void nsVoidArray::Clear()
-{
-  if (mImpl)
-  {
-    mImpl->mCount = 0;
-    // We don't have to free on Clear, but if we have a built-in buffer,
-    // it's worth considering.
-    if (HasAutoBuffer() && IsArrayOwner() &&
-        GetArraySize() > kAutoClearCompactSizeFactor * kAutoBufSize) {
-      SizeTo(0);
-    }
-  }
-}
-
-void nsVoidArray::Compact()
-{
-  if (mImpl)
-  {
-    // XXX NOTE: this is quite inefficient in many cases if we're only
-    // compacting by a little, but some callers care more about memory use.
-    PRInt32 count = Count();
-    if (HasAutoBuffer() && count <= kAutoBufSize)
-    {
-      Impl* oldImpl = mImpl;
-      static_cast<nsAutoVoidArray*>(this)->ResetToAutoBuffer();
-      memcpy(mImpl->mArray, oldImpl->mArray,
-             count * sizeof(mImpl->mArray[0]));
-      free(reinterpret_cast<char *>(oldImpl));
-    }
-    else if (GetArraySize() > count)
-    {
-      SizeTo(Count());
-    }
-  }
-}
-
-// Needed because we want to pass the pointer to the item in the array
-// to the comparator function, not a pointer to the pointer in the array.
-struct VoidArrayComparatorContext {
-  nsVoidArrayComparatorFunc mComparatorFunc;
-  void* mData;
-};
-
-PR_STATIC_CALLBACK(int)
-VoidArrayComparator(const void* aElement1, const void* aElement2, void* aData)
-{
-  VoidArrayComparatorContext* ctx = static_cast<VoidArrayComparatorContext*>(aData);
-  return (*ctx->mComparatorFunc)(*static_cast<void* const*>(aElement1),
-                                 *static_cast<void* const*>(aElement2),
-                                  ctx->mData);
-}
-
-void nsVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData)
-{
-  if (mImpl && mImpl->mCount > 1)
-  {
-    VoidArrayComparatorContext ctx = {aFunc, aData};
-    NS_QuickSort(mImpl->mArray, mImpl->mCount, sizeof(mImpl->mArray[0]),
-                 VoidArrayComparator, &ctx);
-  }
-}
-
-PRBool nsVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData)
-{
-  PRInt32 index = -1;
-  PRBool  running = PR_TRUE;
-
-  if (mImpl)
-  {
-    while (running && (++index < mImpl->mCount))
-    {
-      running = (*aFunc)(mImpl->mArray[index], aData);
-    }
-  }
-  return running;
-}
-
-PRBool nsVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData)
-{
-  PRBool  running = PR_TRUE;
-
-  if (mImpl)
-  {
-    PRInt32 index = Count();
-    while (running && (0 <= --index))
-    {
-      running = (*aFunc)(mImpl->mArray[index], aData);
-    }
-  }
-  return running;
-}
-
-//----------------------------------------------------------------
-// nsAutoVoidArray
-
-nsAutoVoidArray::nsAutoVoidArray()
-  : nsVoidArray()
-{
-  // Don't need to clear it.  Some users just call ReplaceElementAt(),
-  // but we'll clear it at that time if needed to save CPU cycles.
-#if DEBUG_VOIDARRAY
-  mIsAuto = PR_TRUE;
-  ADD_TO_STATS(MaxAuto,0);
-#endif
-  ResetToAutoBuffer();
-}
 
 //----------------------------------------------------------------
 // nsStringArray
diff --git a/xpcom/glue/nsVoidArray.h b/xpcom/glue/nsVoidArray.h
--- a/xpcom/glue/nsVoidArray.h
+++ b/xpcom/glue/nsVoidArray.h
@@ -42,6 +42,10 @@
 #include "nscore.h"
 #include "nsStringGlue.h"
 #include "nsDebug.h"
+#include "nsAllocator.h"
+#include "nsQuickSort.h"
+#include "prbit.h"
+#include "nsCRTGlue.h"
 
 // Comparator callback function for sorting array values.
 typedef int (* PR_CALLBACK nsVoidArrayComparatorFunc)
@@ -50,14 +54,15 @@ typedef int (* PR_CALLBACK nsVoidArrayCo
 // Enumerator callback function. Return PR_FALSE to stop
 typedef PRBool (* PR_CALLBACK nsVoidArrayEnumFunc)(void* aElement, void *aData);
 
-/// A basic zero-based array of void*'s that manages its own memory
-class NS_COM_GLUE nsVoidArray {
+/// A basic zero-based array of void*'s that manages its own memory using the C allocator malloc/free
+template<class Allocator>
+class nsVoidArrayBase {
 public:
-  nsVoidArray();
-  nsVoidArray(PRInt32 aCount);  // initial count of aCount elements set to nsnull
-  ~nsVoidArray();
+  nsVoidArrayBase();
+  nsVoidArrayBase(PRInt32 aCount);  // initial count of aCount elements set to nsnull
+  ~nsVoidArrayBase();
 
-  nsVoidArray& operator=(const nsVoidArray& other);
+  nsVoidArrayBase<Allocator>& operator=(const nsVoidArrayBase<Allocator>& other);
 
   inline PRInt32 Count() const {
     return mImpl ? mImpl->mCount : 0;
@@ -98,7 +103,7 @@ public:
   PRInt32 IndexOf(void* aPossibleElement) const;
 
   PRBool InsertElementAt(void* aElement, PRInt32 aIndex);
-  PRBool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex);
+  PRBool InsertElementsAt(const nsVoidArrayBase<Allocator> &other, PRInt32 aIndex);
 
   PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex);
 
@@ -109,7 +114,7 @@ public:
     return InsertElementAt(aElement, Count());
   }
 
-  PRBool AppendElements(nsVoidArray& aElements) {
+  PRBool AppendElements(nsVoidArrayBase<Allocator>& aElements) {
     return InsertElementsAt(aElements, Count());
   }
 
@@ -130,6 +135,19 @@ public:
   PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData);
 
 protected:
+  /**
+   * Grow the array by at least this many elements at a time.
+   */
+  static const PRInt32 kMinGrowArrayBy = 8;
+  static const PRInt32 kMaxGrowArrayBy = 1024;
+  static const PRInt32 kAutoClearCompactSizeFactor = 4;
+
+  /**
+   * This is the threshold (in bytes) of the mImpl struct, past which
+   * we'll force the array to grow geometrically
+   */
+  static const PRInt32 kLinearThreshold = 24 * sizeof(void *);
+
   PRBool GrowArrayBy(PRInt32 aGrowBy);
 
   struct Impl {
@@ -152,6 +170,31 @@ protected:
     void*   mArray[1];
   };
 
+  /**
+   * Compute the number of bytes requires for the mImpl struct that will
+   * hold |n| elements.
+   */
+  static size_t Sizeof_Impl(int n) {
+    return sizeof(Impl) + sizeof(void*) * (n - 1);
+  }
+
+  /**
+   * Compute the number of elements that an mImpl struct of |size| bytes
+   * will hold.
+   */
+  static int Capacityof_Impl(size_t size) {
+    return (size - sizeof(Impl)) / sizeof(void*) + 1;
+  }
+
+  // Needed because we want to pass the pointer to the item in the array
+  // to the comparator function, not a pointer to the pointer in the array.
+  struct ComparatorContext {
+    nsVoidArrayComparatorFunc mComparatorFunc;
+    void* mData;
+  };
+
+  static int Comparator(const void* aElement1, const void* aElement2, void* aData);
+
   Impl* mImpl;
 #if DEBUG_VOIDARRAY
   PRInt32 mMaxCount;
@@ -179,26 +222,31 @@ protected:
 
 private:
   /// Copy constructors are not allowed
-  nsVoidArray(const nsVoidArray& other);
+  nsVoidArrayBase(const nsVoidArrayBase<Allocator>& other);
 };
 
+typedef nsVoidArrayBase<CAllocator> nsVoidArray;
 
 // A zero-based array with a bit of automatic internal storage
-class NS_COM_GLUE nsAutoVoidArray : public nsVoidArray {
+template<class Allocator>
+class nsAutoVoidArrayBase : public nsVoidArrayBase<Allocator> {
 public:
-  nsAutoVoidArray();
+  typedef nsVoidArrayBase<Allocator> Base;
+
+  nsAutoVoidArrayBase();
 
   void ResetToAutoBuffer()
   {
-    SetArray(reinterpret_cast<Impl*>(mAutoBuf), kAutoBufSize, 0, PR_FALSE,
+    SetArray(reinterpret_cast<typename Base::Impl*>(mAutoBuf), Base::kAutoBufSize, 0, PR_FALSE,
              PR_TRUE);
   }
-  
+
 protected:
   // The internal storage
-  char mAutoBuf[sizeof(Impl) + (kAutoBufSize - 1) * sizeof(void*)];
+  char mAutoBuf[sizeof(typename Base::Impl) + (Base::kAutoBufSize - 1) * sizeof(void*)];
 };
 
+typedef nsAutoVoidArrayBase<CAllocator> nsAutoVoidArray;
 
 class nsString;
 
@@ -438,4 +486,536 @@ private:
   PRBool EnsureArray();
 };
 
+template<class Allocator>
+inline void
+nsVoidArrayBase<Allocator>::SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount,
+				     PRBool aOwner, PRBool aHasAuto)
+{
+  // old mImpl has been realloced and so we don't free/delete it
+  NS_PRECONDITION(newImpl, "can't set size");
+  mImpl = newImpl;
+  mImpl->mCount = aCount;
+  mImpl->mBits = static_cast<PRUint32>(aSize & kArraySizeMask) |
+                 (aOwner ? kArrayOwnerMask : 0) |
+                 (aHasAuto ? kArrayHasAutoBufferMask : 0);
+}
+
+// This does all allocation/reallocation of the array.
+// It also will compact down to N - good for things that might grow a lot
+// at times,  but usually are smaller, like JS deferred GC releases.
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::SizeTo(PRInt32 aSize)
+{
+  PRUint32 oldsize = GetArraySize();
+  PRBool isOwner = IsArrayOwner();
+  PRBool hasAuto = HasAutoBuffer();
+
+  if (aSize == (PRInt32) oldsize)
+    return PR_TRUE; // no change
+
+  if (aSize <= 0)
+  {
+    // free the array if allocated
+    if (mImpl)
+    {
+      if (isOwner)
+      {
+	Allocator::Free(mImpl);
+        if (hasAuto) {
+          static_cast<nsAutoVoidArrayBase<Allocator>*>(this)->ResetToAutoBuffer();
+        }
+        else {
+          mImpl = nsnull;
+        }
+      }
+      else
+      {
+        mImpl->mCount = 0; // nsAutoVoidArray
+      }
+    }
+    return PR_TRUE;
+  }
+
+  if (mImpl && isOwner)
+  {
+    // We currently own an array impl. Resize it appropriately.
+    if (aSize < mImpl->mCount)
+    {
+      // XXX Note: we could also just resize to mCount
+      return PR_TRUE;  // can't make it that small, ignore request
+    }
+
+    Impl* newImpl = reinterpret_cast<Impl*>(Allocator::Realloc(mImpl, Sizeof_Impl(mImpl->mCount), Sizeof_Impl(aSize)));
+    if (!newImpl)
+      return PR_FALSE;
+
+    SetArray(newImpl, aSize, newImpl->mCount, PR_TRUE, hasAuto);
+    return PR_TRUE;
+  }
+
+  if ((PRUint32) aSize < oldsize) {
+    // No point in allocating if it won't free the current Impl anyway.
+    return PR_TRUE;
+  }
+
+  // just allocate an array
+  // allocate the exact size requested
+  Impl* newImpl = reinterpret_cast<Impl*>(Allocator::Alloc(Sizeof_Impl(aSize)));
+  if (!newImpl)
+    return PR_FALSE;
+
+  if (mImpl)
+  {
+    // We must be growing an nsAutoVoidArray - copy since we didn't
+    // realloc.
+    memcpy(newImpl->mArray, mImpl->mArray,
+                  mImpl->mCount * sizeof(mImpl->mArray[0]));
+  }
+
+  SetArray(newImpl, aSize, mImpl ? mImpl->mCount : 0, PR_TRUE, hasAuto);
+  // no memset; handled later in ReplaceElementAt if needed
+  return PR_TRUE;
+}
+
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::GrowArrayBy(PRInt32 aGrowBy)
+{
+  // We have to grow the array. Grow by kMinGrowArrayBy slots if we're
+  // smaller than kLinearThreshold bytes, or a power of two if we're
+  // larger.  This is much more efficient with most memory allocators,
+  // especially if it's very large, or of the allocator is binned.
+  if (aGrowBy < kMinGrowArrayBy)
+    aGrowBy = kMinGrowArrayBy;
+
+  PRUint32 newCapacity = GetArraySize() + aGrowBy;  // Minimum increase
+  PRUint32 newSize = Sizeof_Impl(newCapacity);
+
+  if (newSize >= (PRUint32) kLinearThreshold)
+  {
+    // newCount includes enough space for at least kMinGrowArrayBy new
+    // slots. Select the next power-of-two size in bytes above or
+    // equal to that.
+    // Also, limit the increase in size to about a VM page or two.
+    if (GetArraySize() >= kMaxGrowArrayBy)
+    {
+      newCapacity = GetArraySize() + PR_MAX(kMaxGrowArrayBy,aGrowBy);
+      newSize = Sizeof_Impl(newCapacity);
+    }
+    else
+    {
+      PR_CEILING_LOG2(newSize, newSize);
+      newCapacity = Capacityof_Impl(PR_BIT(newSize));
+    }
+  }
+  // frees old mImpl IF this succeeds
+  if (!SizeTo(newCapacity))
+    return PR_FALSE;
+
+  return PR_TRUE;
+}
+
+template<class Allocator>
+nsVoidArrayBase<Allocator>::nsVoidArrayBase()
+  : mImpl(nsnull)
+{
+  MOZ_COUNT_CTOR(nsVoidArray);
+}
+
+template<class Allocator>
+nsVoidArrayBase<Allocator>::nsVoidArrayBase(PRInt32 aCount)
+  : mImpl(nsnull)
+{
+  MOZ_COUNT_CTOR(nsVoidArray);
+  SizeTo(aCount);
+}
+
+template<class Allocator>
+nsVoidArrayBase<Allocator>&
+nsVoidArrayBase<Allocator>::operator=(const nsVoidArrayBase<Allocator>& other)
+{
+  PRInt32 otherCount = other.Count();
+  PRInt32 maxCount = GetArraySize();
+  if (otherCount)
+  {
+    if (otherCount > maxCount)
+    {
+      // frees old mImpl IF this succeeds
+      if (!GrowArrayBy(otherCount-maxCount))
+        return *this;      // XXX The allocation failed - don't do anything
+
+      memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
+      mImpl->mCount = otherCount;
+    }
+    else
+    {
+      // the old array can hold the new array
+      memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0]));
+      mImpl->mCount = otherCount;
+      // if it shrank a lot, compact it anyways
+      if ((otherCount*2) < maxCount && maxCount > 100)
+      {
+        Compact();  // shrank by at least 50 entries
+      }
+    }
+#if DEBUG_VOIDARRAY
+     if (mImpl->mCount > mMaxCount &&
+         mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
+     {
+       MaxElements[mImpl->mCount]++;
+       MaxElements[mMaxCount]--;
+       mMaxCount = mImpl->mCount;
+     }
+#endif
+  }
+  else
+  {
+    // Why do we drop the buffer here when we don't in Clear()?
+    SizeTo(0);
+  }
+
+  return *this;
+}
+
+template<class Allocator>
+nsVoidArrayBase<Allocator>::~nsVoidArrayBase()
+{
+  MOZ_COUNT_DTOR(nsVoidArray);
+  if (mImpl && IsArrayOwner())
+    Allocator::Free(mImpl);
+}
+
+template<class Allocator>
+PRInt32 nsVoidArrayBase<Allocator>::IndexOf(void* aPossibleElement) const
+{
+  if (mImpl)
+  {
+    void** ap = mImpl->mArray;
+    void** end = ap + mImpl->mCount;
+    while (ap < end)
+    {
+      if (*ap == aPossibleElement)
+      {
+        return ap - mImpl->mArray;
+      }
+      ap++;
+    }
+  }
+  return -1;
+}
+
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::InsertElementAt(void* aElement, PRInt32 aIndex)
+{
+  PRInt32 oldCount = Count();
+  NS_ASSERTION(aIndex >= 0,"InsertElementAt(negative index)");
+  if (PRUint32(aIndex) > PRUint32(oldCount))
+  {
+    // An invalid index causes the insertion to fail
+    // Invalid indexes are ones that add more than one entry to the
+    // array (i.e., they can append).
+    return PR_FALSE;
+  }
+
+  if (oldCount >= GetArraySize())
+  {
+    if (!GrowArrayBy(1))
+      return PR_FALSE;
+  }
+  // else the array is already large enough
+
+  PRInt32 slide = oldCount - aIndex;
+  if (0 != slide)
+  {
+    // Slide data over to make room for the insertion
+    memmove(mImpl->mArray + aIndex + 1, mImpl->mArray + aIndex,
+            slide * sizeof(mImpl->mArray[0]));
+  }
+
+  mImpl->mArray[aIndex] = aElement;
+  mImpl->mCount++;
+
+#if DEBUG_VOIDARRAY
+  if (mImpl->mCount > mMaxCount &&
+      mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
+  {
+    MaxElements[mImpl->mCount]++;
+    MaxElements[mMaxCount]--;
+    mMaxCount = mImpl->mCount;
+  }
+#endif
+
+  return PR_TRUE;
+}
+
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::InsertElementsAt(const nsVoidArrayBase<Allocator>& other, PRInt32 aIndex)
+{
+  PRInt32 oldCount = Count();
+  PRInt32 otherCount = other.Count();
+
+  NS_ASSERTION(aIndex >= 0,"InsertElementsAt(negative index)");
+  if (PRUint32(aIndex) > PRUint32(oldCount))
+  {
+    // An invalid index causes the insertion to fail
+    // Invalid indexes are ones that are more than one entry past the end of
+    // the array (i.e., they can append).
+    return PR_FALSE;
+  }
+
+  if (oldCount + otherCount > GetArraySize())
+  {
+    if (!GrowArrayBy(otherCount))
+      return PR_FALSE;;
+  }
+  // else the array is already large enough
+
+  PRInt32 slide = oldCount - aIndex;
+  if (0 != slide)
+  {
+    // Slide data over to make room for the insertion
+    memmove(mImpl->mArray + aIndex + otherCount, mImpl->mArray + aIndex,
+            slide * sizeof(mImpl->mArray[0]));
+  }
+
+  for (PRInt32 i = 0; i < otherCount; i++)
+  {
+    // copy all the elements (destroys aIndex)
+    mImpl->mArray[aIndex++] = other.mImpl->mArray[i];
+    mImpl->mCount++;
+  }
+
+#if DEBUG_VOIDARRAY
+  if (mImpl->mCount > mMaxCount &&
+      mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
+  {
+    MaxElements[mImpl->mCount]++;
+    MaxElements[mMaxCount]--;
+    mMaxCount = mImpl->mCount;
+  }
+#endif
+
+  return PR_TRUE;
+}
+
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::ReplaceElementAt(void* aElement, PRInt32 aIndex)
+{
+  NS_ASSERTION(aIndex >= 0,"ReplaceElementAt(negative index)");
+  if (aIndex < 0)
+    return PR_FALSE;
+
+  // Unlike InsertElementAt, ReplaceElementAt can implicitly add more
+  // than just the one element to the array.
+  if (PRUint32(aIndex) >= PRUint32(GetArraySize()))
+  {
+    PRInt32 oldCount = Count();
+    PRInt32 requestedCount = aIndex + 1;
+    PRInt32 growDelta = requestedCount - oldCount;
+
+    // frees old mImpl IF this succeeds
+    if (!GrowArrayBy(growDelta))
+      return PR_FALSE;
+  }
+
+  mImpl->mArray[aIndex] = aElement;
+  if (aIndex >= mImpl->mCount)
+  {
+    // Make sure that any entries implicitly added to the array by this
+    // ReplaceElementAt are cleared to 0.  Some users of this assume that.
+    // This code means we don't have to memset when we allocate an array.
+    if (aIndex > mImpl->mCount) // note: not >=
+    {
+      // For example, if mCount is 2, and we do a ReplaceElementAt for
+      // element[5], then we need to set three entries ([2], [3], and [4])
+      // to 0.
+      memset(&mImpl->mArray[mImpl->mCount], 0,
+             (aIndex - mImpl->mCount) * sizeof(mImpl->mArray[0]));
+    }
+    
+     mImpl->mCount = aIndex + 1;
+
+#if DEBUG_VOIDARRAY
+     if (mImpl->mCount > mMaxCount &&
+         mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0])))
+     {
+       MaxElements[mImpl->mCount]++;
+       MaxElements[mMaxCount]--;
+       mMaxCount = mImpl->mCount;
+     }
+#endif
+  }
+
+  return PR_TRUE;
+}
+
+// useful for doing LRU arrays
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::MoveElement(PRInt32 aFrom, PRInt32 aTo)
+{
+  void *tempElement;
+
+  if (aTo == aFrom)
+    return PR_TRUE;
+
+  NS_ASSERTION(aTo >= 0 && aFrom >= 0,"MoveElement(negative index)");
+  if (aTo >= Count() || aFrom >= Count())
+  {
+    // can't extend the array when moving an element.  Also catches mImpl = null
+    return PR_FALSE;
+  }
+  tempElement = mImpl->mArray[aFrom];
+
+  if (aTo < aFrom)
+  {
+    // Moving one element closer to the head; the elements inbetween move down
+    memmove(mImpl->mArray + aTo + 1, mImpl->mArray + aTo,
+            (aFrom-aTo) * sizeof(mImpl->mArray[0]));
+    mImpl->mArray[aTo] = tempElement;
+  }
+  else // already handled aFrom == aTo
+  {
+    // Moving one element closer to the tail; the elements inbetween move up
+    memmove(mImpl->mArray + aFrom, mImpl->mArray + aFrom + 1,
+            (aTo-aFrom) * sizeof(mImpl->mArray[0]));
+    mImpl->mArray[aTo] = tempElement;
+  }
+
+  return PR_TRUE;
+}
+
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount)
+{
+  PRInt32 oldCount = Count();
+  NS_ASSERTION(aIndex >= 0,"RemoveElementsAt(negative index)");
+  if (PRUint32(aIndex) >= PRUint32(oldCount))
+  {
+    // An invalid index causes the replace to fail
+    return PR_FALSE;
+  }
+  // Limit to available entries starting at aIndex
+  if (aCount + aIndex > oldCount)
+    aCount = oldCount - aIndex;
+
+  // We don't need to move any elements if we're removing the
+  // last element in the array
+  if (aIndex < (oldCount - aCount))
+  {
+    memmove(mImpl->mArray + aIndex, mImpl->mArray + aIndex + aCount,
+            (oldCount - (aIndex + aCount)) * sizeof(mImpl->mArray[0]));
+  }
+
+  mImpl->mCount -= aCount;
+  return PR_TRUE;
+}
+
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::RemoveElement(void* aElement)
+{
+  PRInt32 theIndex = IndexOf(aElement);
+  if (theIndex != -1)
+    return RemoveElementAt(theIndex);
+
+  return PR_FALSE;
+}
+
+template<class Allocator>
+void nsVoidArrayBase<Allocator>::Clear()
+{
+  if (mImpl)
+  {
+    mImpl->mCount = 0;
+    // We don't have to free on Clear, but if we have a built-in buffer,
+    // it's worth considering.
+    if (HasAutoBuffer() && IsArrayOwner() &&
+        GetArraySize() > kAutoClearCompactSizeFactor * kAutoBufSize) {
+      SizeTo(0);
+    }
+  }
+}
+
+template<class Allocator>
+void nsVoidArrayBase<Allocator>::Compact()
+{
+  if (mImpl)
+  {
+    // XXX NOTE: this is quite inefficient in many cases if we're only
+    // compacting by a little, but some callers care more about memory use.
+    PRInt32 count = Count();
+    if (HasAutoBuffer() && count <= kAutoBufSize)
+    {
+      Impl* oldImpl = mImpl;
+      static_cast<nsAutoVoidArray*>(this)->ResetToAutoBuffer();
+      memcpy(mImpl->mArray, oldImpl->mArray,
+             count * sizeof(mImpl->mArray[0]));
+      Allocator::Free(reinterpret_cast<char *>(oldImpl));
+    }
+    else if (GetArraySize() > count)
+    {
+      SizeTo(Count());
+    }
+  }
+}
+
+template<class Allocator>
+int
+nsVoidArrayBase<Allocator>::Comparator(const void* aElement1, const void* aElement2, void* aData)
+{
+  ComparatorContext* ctx = static_cast<ComparatorContext*>(aData);
+  return (*ctx->mComparatorFunc)(*static_cast<void* const*>(aElement1),
+                                 *static_cast<void* const*>(aElement2),
+                                  ctx->mData);
+}
+
+template<class Allocator>
+void nsVoidArrayBase<Allocator>::Sort(nsVoidArrayComparatorFunc aFunc, void* aData)
+{
+  if (mImpl && mImpl->mCount > 1)
+  {
+    ComparatorContext ctx = {aFunc, aData};
+    NS_QuickSort(mImpl->mArray, mImpl->mCount, sizeof(mImpl->mArray[0]),
+                 Comparator, &ctx);
+  }
+}
+
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData)
+{
+  PRInt32 index = -1;
+  PRBool  running = PR_TRUE;
+
+  if (mImpl)
+  {
+    while (running && (++index < mImpl->mCount))
+    {
+      running = (*aFunc)(mImpl->mArray[index], aData);
+    }
+  }
+  return running;
+}
+
+template<class Allocator>
+PRBool nsVoidArrayBase<Allocator>::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData)
+{
+  PRBool  running = PR_TRUE;
+
+  if (mImpl)
+  {
+    PRInt32 index = Count();
+    while (running && (0 <= --index))
+    {
+      running = (*aFunc)(mImpl->mArray[index], aData);
+    }
+  }
+  return running;
+}
+
+template<class Allocator>
+nsAutoVoidArrayBase<Allocator>::nsAutoVoidArrayBase()
+{
+  // Don't need to clear it.  Some users just call ReplaceElementAt(),
+  // but we'll clear it at that time if needed to save CPU cycles.
+  ResetToAutoBuffer();
+}
+
 #endif /* nsVoidArray_h___ */
diff --git a/xpcom/glue/objs.mk b/xpcom/glue/objs.mk
--- a/xpcom/glue/objs.mk
+++ b/xpcom/glue/objs.mk
@@ -41,6 +41,7 @@ XPCOM_GLUE_SRC_CSRCS = $(addprefix $(top
 XPCOM_GLUE_SRC_CSRCS = $(addprefix $(topsrcdir)/xpcom/glue/, $(XPCOM_GLUE_SRC_LCSRCS))
 
 XPCOM_GLUE_SRC_LCPPSRCS =        \
+  nsAllocator.cpp                \
   nsArrayEnumerator.cpp          \
   nsArrayUtils.cpp               \
   nsCategoryCache.cpp            \