diff --git a/mozilla/content/html/content/src/nsHTMLAtoms.cpp b/mozilla/content/html/content/src/nsHTMLAtoms.cpp
index 224874fab32..0fd9bb7c0cd 100644
--- a/mozilla/content/html/content/src/nsHTMLAtoms.cpp
+++ b/mozilla/content/html/content/src/nsHTMLAtoms.cpp
@@ -49,7 +49,7 @@ void nsHTMLAtoms::AddRefAtoms()
{
if (0 == gRefCnt++) {
// create atoms
-#define HTML_ATOM(_name, _value) _name = NS_NewAtom(_value);
+#define HTML_ATOM(_name, _value) _name = NS_NewPermanentAtom(_value);
#include "nsHTMLAtomList.h"
#undef HTML_ATOM
}
diff --git a/mozilla/content/shared/src/nsCSSAtoms.cpp b/mozilla/content/shared/src/nsCSSAtoms.cpp
index 854982378c0..d9ef7923e15 100644
--- a/mozilla/content/shared/src/nsCSSAtoms.cpp
+++ b/mozilla/content/shared/src/nsCSSAtoms.cpp
@@ -49,7 +49,7 @@ void nsCSSAtoms::AddRefAtoms()
{
if (0 == gRefCnt++) {
// create atoms
-#define CSS_ATOM(_name, _value) _name = NS_NewAtom(_value);
+#define CSS_ATOM(_name, _value) _name = NS_NewPermanentAtom(_value);
#include "nsCSSAtomList.h"
#undef CSS_ATOM
}
diff --git a/mozilla/content/shared/src/nsHTMLAtoms.cpp b/mozilla/content/shared/src/nsHTMLAtoms.cpp
index 224874fab32..0fd9bb7c0cd 100644
--- a/mozilla/content/shared/src/nsHTMLAtoms.cpp
+++ b/mozilla/content/shared/src/nsHTMLAtoms.cpp
@@ -49,7 +49,7 @@ void nsHTMLAtoms::AddRefAtoms()
{
if (0 == gRefCnt++) {
// create atoms
-#define HTML_ATOM(_name, _value) _name = NS_NewAtom(_value);
+#define HTML_ATOM(_name, _value) _name = NS_NewPermanentAtom(_value);
#include "nsHTMLAtomList.h"
#undef HTML_ATOM
}
diff --git a/mozilla/content/shared/src/nsLayoutAtoms.cpp b/mozilla/content/shared/src/nsLayoutAtoms.cpp
index 2f65a33fdcc..0f130c46da7 100644
--- a/mozilla/content/shared/src/nsLayoutAtoms.cpp
+++ b/mozilla/content/shared/src/nsLayoutAtoms.cpp
@@ -49,7 +49,7 @@ void nsLayoutAtoms::AddRefAtoms()
{
if (0 == gRefCnt++) {
// create atoms
-#define LAYOUT_ATOM(_name, _value) _name = NS_NewAtom(_value);
+#define LAYOUT_ATOM(_name, _value) _name = NS_NewPermanentAtom(_value);
#include "nsLayoutAtomList.h"
#undef LAYOUT_ATOM
}
diff --git a/mozilla/content/shared/src/nsXULAtoms.cpp b/mozilla/content/shared/src/nsXULAtoms.cpp
index c295bfb384a..9d8f5643125 100644
--- a/mozilla/content/shared/src/nsXULAtoms.cpp
+++ b/mozilla/content/shared/src/nsXULAtoms.cpp
@@ -71,7 +71,7 @@ void nsXULAtoms::AddRefAtoms() {
}
// now register the atoms
-#define XUL_ATOM(_name, _value) _name = NS_NewAtom(_value);
+#define XUL_ATOM(_name, _value) _name = NS_NewPermanentAtom(_value);
#include "nsXULAtomList.h"
#undef XUL_ATOM
}
diff --git a/mozilla/layout/base/nsLayoutAtoms.cpp b/mozilla/layout/base/nsLayoutAtoms.cpp
index 2f65a33fdcc..0f130c46da7 100644
--- a/mozilla/layout/base/nsLayoutAtoms.cpp
+++ b/mozilla/layout/base/nsLayoutAtoms.cpp
@@ -49,7 +49,7 @@ void nsLayoutAtoms::AddRefAtoms()
{
if (0 == gRefCnt++) {
// create atoms
-#define LAYOUT_ATOM(_name, _value) _name = NS_NewAtom(_value);
+#define LAYOUT_ATOM(_name, _value) _name = NS_NewPermanentAtom(_value);
#include "nsLayoutAtomList.h"
#undef LAYOUT_ATOM
}
diff --git a/mozilla/layout/mathml/content/src/nsMathMLAtoms.cpp b/mozilla/layout/mathml/content/src/nsMathMLAtoms.cpp
index e407f226465..0baaa3c205f 100644
--- a/mozilla/layout/mathml/content/src/nsMathMLAtoms.cpp
+++ b/mozilla/layout/mathml/content/src/nsMathMLAtoms.cpp
@@ -59,7 +59,7 @@ void nsMathMLAtoms::AddRefAtoms() {
}
// now register the atoms
-#define MATHML_ATOM(_name, _value) _name = NS_NewAtom(_value);
+#define MATHML_ATOM(_name, _value) _name = NS_NewPermanentAtom(_value);
#include "nsMathMLAtomList.h"
#undef MATHML_ATOM
}
diff --git a/mozilla/layout/svg/content/src/nsSVGAtoms.cpp b/mozilla/layout/svg/content/src/nsSVGAtoms.cpp
index 3bc9fc1ce53..39d4aaafa5d 100644
--- a/mozilla/layout/svg/content/src/nsSVGAtoms.cpp
+++ b/mozilla/layout/svg/content/src/nsSVGAtoms.cpp
@@ -76,7 +76,7 @@ void nsSVGAtoms::AddRefAtoms() {
}
// now register the atoms
-#define SVG_ATOM(_name, _value) _name = NS_NewAtom(_value);
+#define SVG_ATOM(_name, _value) _name = NS_NewPermanentAtom(_value);
#include "nsSVGAtomList.h"
#undef SVG_ATOM
}
diff --git a/mozilla/widget/src/xpwidgets/nsWidgetAtoms.cpp b/mozilla/widget/src/xpwidgets/nsWidgetAtoms.cpp
index af5bf7619ad..e38ce598055 100644
--- a/mozilla/widget/src/xpwidgets/nsWidgetAtoms.cpp
+++ b/mozilla/widget/src/xpwidgets/nsWidgetAtoms.cpp
@@ -50,7 +50,7 @@ void nsWidgetAtoms::AddRefAtoms() {
if (gRefCnt == 0) {
// now register the atoms
-#define WIDGET_ATOM(_name, _value) _name = NS_NewAtom(_value);
+#define WIDGET_ATOM(_name, _value) _name = NS_NewPermanentAtom(_value);
#include "nsWidgetAtomList.h"
#undef WIDGET_ATOM
}
diff --git a/mozilla/xpcom/build/nsXPComInit.cpp b/mozilla/xpcom/build/nsXPComInit.cpp
index 5d66d3600b8..09d8b7c4f04 100644
--- a/mozilla/xpcom/build/nsXPComInit.cpp
+++ b/mozilla/xpcom/build/nsXPComInit.cpp
@@ -89,6 +89,7 @@
#include "nsFastLoadService.h"
#include "nsAtomService.h"
+#include "nsAtomTable.h"
#include "nsTraceRefcnt.h"
#include "nsTimelineService.h"
diff --git a/mozilla/xpcom/ds/nsAtomService.cpp b/mozilla/xpcom/ds/nsAtomService.cpp
index 393e53d72fb..cf79d965689 100644
--- a/mozilla/xpcom/ds/nsAtomService.cpp
+++ b/mozilla/xpcom/ds/nsAtomService.cpp
@@ -52,8 +52,6 @@ nsAtomService::~nsAtomService()
nsresult
nsAtomService::GetAtom(const PRUnichar *aString, nsIAtom ** aResult)
{
- NS_ENSURE_ARG_POINTER(aResult);
-
*aResult = NS_NewAtom(aString);
if (!*aResult)
@@ -61,3 +59,14 @@ nsAtomService::GetAtom(const PRUnichar *aString, nsIAtom ** aResult)
return NS_OK;
}
+
+nsresult
+nsAtomService::GetPermanentAtom(const PRUnichar *aString, nsIAtom ** aResult)
+{
+ *aResult = NS_NewPermanentAtom(aString);
+
+ if (!*aResult)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ return NS_OK;
+}
diff --git a/mozilla/xpcom/ds/nsAtomTable.cpp b/mozilla/xpcom/ds/nsAtomTable.cpp
index 4f7d2246ff0..7dc646e0c01 100644
--- a/mozilla/xpcom/ds/nsAtomTable.cpp
+++ b/mozilla/xpcom/ds/nsAtomTable.cpp
@@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:cindent:ts=2:et:sw=2:
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
@@ -38,76 +39,161 @@
#include "nsAtomTable.h"
#include "nsString.h"
#include "nsCRT.h"
-#include "plhash.h"
+#include "pldhash.h"
+#include "prenv.h"
#include "nsISizeOfHandler.h"
-#include "nslog.h"
-
-NS_IMPL_LOG(nsAtomTableLog)
-#define PRINTF NS_LOG_PRINTF(nsAtomTableLog)
-#define FLUSH NS_LOG_FLUSH(nsAtomTableLog)
/**
* The shared hash table for atom lookups.
+ *
+ * XXX This should be manipulated in a threadsafe way or we should make
+ * sure it's only manipulated from the main thread. Probably the latter
+ * is better, since the former would hurt performance.
+ *
+ * If |gAtomTable.entryCount| is 0, then the table is uninitialized.
*/
-static nsrefcnt gAtoms;
-static struct PLHashTable* gAtomHashTable;
+static PLDHashTable gAtomTable;
-#if defined(DEBUG) && (defined(XP_UNIX) || defined(XP_PC))
-static PRIntn PR_CALLBACK
-DumpAtomLeaks(PLHashEntry *he, PRIntn index, void *arg)
+struct AtomTableEntry : public PLDHashEntryHdr {
+ AtomImpl *mAtom;
+};
+
+PR_STATIC_CALLBACK(const void *)
+AtomTableGetKey(PLDHashTable *table, PLDHashEntryHdr *entry)
{
- AtomImpl* atom = (AtomImpl*) he->value;
- if (atom) {
- nsAutoString tmp;
- atom->ToString(tmp);
- fputs(NS_LossyConvertUCS2toASCII(tmp).get(), stdout);
+ AtomTableEntry *he = NS_STATIC_CAST(AtomTableEntry*, entry);
+ return he->mAtom->mString;
+}
+
+PR_STATIC_CALLBACK(PLDHashNumber)
+AtomTableHashKey(PLDHashTable *table, const void *key)
+{
+ return nsCRT::HashCode(NS_STATIC_CAST(const PRUnichar*,key));
+}
+
+PR_STATIC_CALLBACK(PRBool)
+AtomTableMatchKey(PLDHashTable *table,
+ const PLDHashEntryHdr *entry,
+ const void *key)
+{
+ const AtomTableEntry *he = NS_STATIC_CAST(const AtomTableEntry*, entry);
+ const PRUnichar* keyStr = NS_STATIC_CAST(const PRUnichar*, key);
+ return nsCRT::strcmp(keyStr, he->mAtom->mString) == 0;
+}
+
+PR_STATIC_CALLBACK(void)
+AtomTableClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
+{
+ AtomTableEntry *he = NS_STATIC_CAST(AtomTableEntry*, entry);
+ AtomImpl *atom = he->mAtom;
+ he->mAtom = 0;
+ he->keyHash = 0;
+
+ // Normal |AtomImpl| atoms are deleted when their refcount hits 0, and
+ // they then remove themselves from the table. In other words, they
+ // are owned by the callers who own references to them.
+ // |PermanentAtomImpl| permanent atoms ignore their refcount and are
+ // deleted when they are removed from the table at table destruction.
+ // In other words, they are owned by the atom table.
+ if (atom->IsPermanent())
+ delete atom;
+}
+
+static PLDHashTableOps AtomTableOps = {
+ PL_DHashAllocTable,
+ PL_DHashFreeTable,
+ AtomTableGetKey,
+ AtomTableHashKey,
+ AtomTableMatchKey,
+ PL_DHashMoveEntryStub,
+ AtomTableClearEntry,
+ PL_DHashFinalizeStub,
+ NULL
+};
+
+
+#ifdef DEBUG
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+DumpAtomLeaks(PLDHashTable *table, PLDHashEntryHdr *he,
+ PRUint32 index, void *arg)
+{
+ AtomTableEntry *entry = NS_STATIC_CAST(AtomTableEntry*, he);
+ AtomImpl* atom = entry->mAtom;
+ if (!atom->IsPermanent()) {
+ ++*NS_STATIC_CAST(PRUint32*, arg);
+ const PRUnichar *str;
+ atom->GetUnicode(&str);
+ fputs(NS_LossyConvertUCS2toASCII(str).get(), stdout);
fputs("\n", stdout);
}
- return HT_ENUMERATE_NEXT;
+ return PL_DHASH_NEXT;
}
+
#endif
-NS_COM void NS_PurgeAtomTable(void)
+void NS_PurgeAtomTable()
{
- if (gAtomHashTable) {
-#if defined(DEBUG) && (defined(XP_UNIX) || defined(XP_PC))
- if (gAtoms) {
- if (NS_LOG_ENABLED(nsAtomTableLog)) {
- PRINTF("*** leaking %d atoms\n", gAtoms);
- PL_HashTableEnumerateEntries(gAtomHashTable, DumpAtomLeaks, 0);
- }
+ if (gAtomTable.entryCount) {
+#ifdef DEBUG
+ if (PR_GetEnv("MOZ_DUMP_ATOM_LEAKS")) {
+ PRUint32 leaked = 0;
+ printf("*** %d atoms still exist (including permanent):\n",
+ gAtomTable.entryCount);
+ PL_DHashTableEnumerate(&gAtomTable, DumpAtomLeaks, &leaked);
+ printf("*** %u non-permanent atoms leaked\n", leaked);
}
#endif
- PL_HashTableDestroy(gAtomHashTable);
- gAtomHashTable = nsnull;
+ PL_DHashTableFinish(&gAtomTable);
+ gAtomTable.entryCount = 0;
}
}
AtomImpl::AtomImpl()
{
- NS_INIT_REFCNT();
- // Every live atom holds a reference on the atom hashtable
- gAtoms++;
+ NS_INIT_ISUPPORTS();
}
AtomImpl::~AtomImpl()
{
- NS_PRECONDITION(nsnull != gAtomHashTable, "null atom hashtable");
- if (nsnull != gAtomHashTable) {
-
- PL_HashTableRemove(gAtomHashTable, mString);
- nsrefcnt cnt = --gAtoms;
- if (0 == cnt) {
- // When the last atom is destroyed, the atom arena is destroyed
- NS_ASSERTION(0 == gAtomHashTable->nentries, "bad atom table");
- PL_HashTableDestroy(gAtomHashTable);
- gAtomHashTable = nsnull;
+ NS_PRECONDITION(gAtomTable.entryCount, "uninitialized atom hashtable");
+ // Permanent atoms are removed from the hashtable at shutdown, and we
+ // don't want to remove them twice. See comment above in
+ // |AtomTableClearEntry|.
+ if (!IsPermanent()) {
+ PL_DHashTableOperate(&gAtomTable, mString, PL_DHASH_REMOVE);
+ if (gAtomTable.entryCount == 0) {
+ PL_DHashTableFinish(&gAtomTable);
+ NS_ASSERTION(gAtomTable.entryCount == 0,
+ "PL_DHashTableFinish changed the entry count");
}
}
}
NS_IMPL_THREADSAFE_ISUPPORTS1(AtomImpl, nsIAtom)
+NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::AddRef()
+{
+ return 2;
+}
+
+NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::Release()
+{
+ return 1;
+}
+
+/* virtual */ PRBool
+AtomImpl::IsPermanent()
+{
+ return PR_FALSE;
+}
+
+/* virtual */ PRBool
+PermanentAtomImpl::IsPermanent()
+{
+ return PR_TRUE;
+}
+
void* AtomImpl::operator new ( size_t size, const nsAReadableString& aString )
{
/*
@@ -120,7 +206,7 @@ void* AtomImpl::operator new ( size_t size, const nsAReadableString& aString )
http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsSharedString.h#174
*/
size += aString.Length() * sizeof(PRUnichar);
- AtomImpl* ii = (AtomImpl*) ::operator new(size);
+ AtomImpl* ii = NS_STATIC_CAST(AtomImpl*, ::operator new(size));
PRUnichar* toBegin = &ii->mString[0];
nsReadingIterator fromBegin, fromEnd;
@@ -128,6 +214,14 @@ void* AtomImpl::operator new ( size_t size, const nsAReadableString& aString )
return ii;
}
+void* PermanentAtomImpl::operator new ( size_t size, AtomImpl* aAtom ) {
+ NS_ASSERTION(!aAtom->IsPermanent(),
+ "converting atom that's already permanent");
+
+ // Just let the constructor overwrite the vtable pointer.
+ return aAtom;
+}
+
NS_IMETHODIMP
AtomImpl::ToString(nsAWritableString& aBuf) /*FIX: const */
{
@@ -138,7 +232,7 @@ AtomImpl::ToString(nsAWritableString& aBuf) /*FIX: const */
NS_IMETHODIMP
AtomImpl::GetUnicode(const PRUnichar **aResult) /*FIX: const */
{
- NS_ENSURE_ARG_POINTER(aResult);
+ NS_PRECONDITION(aResult, "null out param");
*aResult = mString;
return NS_OK;
}
@@ -147,61 +241,84 @@ NS_IMETHODIMP
AtomImpl::SizeOf(nsISizeOfHandler* aHandler, PRUint32* _retval) /*FIX: const */
{
#ifdef DEBUG
- NS_ENSURE_ARG_POINTER(_retval);
- PRUint32 sum = sizeof(*this) + nsCRT::strlen(mString) * sizeof(PRUnichar);
- *_retval = sum;
+ NS_PRECONDITION(_retval, "null out param");
+ *_retval = sizeof(*this) + nsCRT::strlen(mString) * sizeof(PRUnichar);
#endif
return NS_OK;
}
//----------------------------------------------------------------------
-static PLHashNumber HashKey(const PRUnichar* k)
-{
- return nsCRT::HashCode(k);
-}
-
-static PRIntn CompareKeys( const PRUnichar* k1, const PRUnichar* k2 )
-{
- return nsCRT::strcmp(k1, k2) == 0;
-}
-
NS_COM nsIAtom* NS_NewAtom(const char* isolatin1)
{
return NS_NewAtom(NS_ConvertASCIItoUCS2(isolatin1));
}
-NS_COM nsIAtom* NS_NewAtom( const nsAReadableString& aString )
+NS_COM nsIAtom* NS_NewPermanentAtom(const char* isolatin1)
{
- if ( !gAtomHashTable )
- gAtomHashTable = PL_NewHashTable(2048, (PLHashFunction)HashKey,
- (PLHashComparator)CompareKeys,
- (PLHashComparator)0, 0, 0);
+ return NS_NewPermanentAtom(NS_ConvertASCIItoUCS2(isolatin1));
+}
- const nsPromiseFlatString& flat = PromiseFlatString(aString);
- const PRUnichar *str = flat.get();
+static AtomTableEntry* GetAtomHashEntry(const nsAString& aString)
+{
+ if ( !gAtomTable.entryCount )
+ PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0,
+ sizeof(AtomTableEntry), 2048);
- PRUint32 hashCode = HashKey(str);
+ return NS_STATIC_CAST(AtomTableEntry*,
+ PL_DHashTableOperate(&gAtomTable,
+ PromiseFlatString(aString).get(),
+ PL_DHASH_ADD));
+}
- PLHashEntry** hep = PL_HashTableRawLookup(gAtomHashTable, hashCode, str);
+NS_COM nsIAtom* NS_NewAtom( const nsAString& aString )
+{
+ AtomTableEntry *he = GetAtomHashEntry(aString);
+ AtomImpl* atom = he->mAtom;
- PLHashEntry* he = *hep;
-
- AtomImpl* id;
-
- if ( he ) {
- // if we found one, great
- id = NS_STATIC_CAST(AtomImpl*, he->value);
- } else {
- // otherwise, we'll make a new atom
- id = new (aString) AtomImpl();
- if ( id ) {
- PL_HashTableRawAdd(gAtomHashTable, hep, hashCode, id->mString, id);
+ if (!atom) {
+ atom = new (aString) AtomImpl();
+ he->mAtom = atom;
+ if (!atom) {
+ PL_DHashTableRawRemove(&gAtomTable, he);
+ return nsnull;
}
}
- NS_IF_ADDREF(id);
- return id;
+ NS_ADDREF(atom);
+ return atom;
+}
+
+NS_COM nsIAtom* NS_NewPermanentAtom( const nsAString& aString )
+{
+ AtomTableEntry *he = GetAtomHashEntry(aString);
+ AtomImpl* atom = he->mAtom;
+
+ if (atom) {
+ // ensure that it's permanent
+ if (!atom->IsPermanent()) {
+#ifdef NS_BUILD_REFCNT_LOGGING
+ {
+ nsrefcnt refcount = atom->GetRefCount();
+ do {
+ NS_LOG_RELEASE(atom, --refcount, "AtomImpl");
+ } while (refcount);
+ }
+#endif
+ atom = new (atom) PermanentAtomImpl();
+ }
+ } else {
+ // otherwise, make a new atom
+ atom = new (aString) PermanentAtomImpl();
+ he->mAtom = atom;
+ if ( !atom ) {
+ PL_DHashTableRawRemove(&gAtomTable, he);
+ return nsnull;
+ }
+ }
+
+ NS_ADDREF(atom);
+ return atom;
}
NS_COM nsIAtom* NS_NewAtom( const PRUnichar* str )
@@ -209,10 +326,12 @@ NS_COM nsIAtom* NS_NewAtom( const PRUnichar* str )
return NS_NewAtom(nsDependentString(str));
}
+NS_COM nsIAtom* NS_NewPermanentAtom( const PRUnichar* str )
+{
+ return NS_NewPermanentAtom(nsDependentString(str));
+}
+
NS_COM nsrefcnt NS_GetNumberOfAtoms(void)
{
- if (nsnull != gAtomHashTable) {
- NS_PRECONDITION(nsrefcnt(gAtomHashTable->nentries) == gAtoms, "bad atom table");
- }
- return gAtoms;
+ return gAtomTable.entryCount;
}
diff --git a/mozilla/xpcom/ds/nsAtomTable.h b/mozilla/xpcom/ds/nsAtomTable.h
index 9c17a37ab15..b1bfba068b8 100644
--- a/mozilla/xpcom/ds/nsAtomTable.h
+++ b/mozilla/xpcom/ds/nsAtomTable.h
@@ -40,6 +40,12 @@
#include "nsIAtom.h"
+/**
+ * A threadsafely-refcounted implementation of nsIAtom. Note that
+ * AtomImpl objects are sometimes converted into PermanentAtomImpl
+ * objects using placement new and just overwriting the vtable pointer.
+ */
+
class AtomImpl : public nsIAtom {
public:
AtomImpl();
@@ -48,15 +54,40 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIATOM
- void* operator new(size_t size, const nsAReadableString& aString);
+ virtual PRBool IsPermanent();
+
+ void* operator new(size_t size, const nsAString& aString);
void operator delete(void* ptr) {
::operator delete(ptr);
}
+ // for |#ifdef NS_BUILD_REFCNT_LOGGING| access to reference count
+ nsrefcnt GetRefCount() { return mRefCnt; }
+
// Actually more; 0 terminated. This slot is reserved for the
// terminating zero.
PRUnichar mString[1];
};
+/**
+ * A non-refcounted implementation of nsIAtom.
+ */
+
+class PermanentAtomImpl : public AtomImpl {
+public:
+ NS_IMETHOD_(nsrefcnt) AddRef();
+ NS_IMETHOD_(nsrefcnt) Release();
+
+ virtual PRBool IsPermanent();
+
+ void* operator new(size_t size, const nsAReadableString& aString) {
+ return AtomImpl::operator new(size, aString);
+ }
+ void* operator new(size_t size, AtomImpl* aAtom);
+
+};
+
+void NS_PurgeAtomTable();
+
#endif // nsAtomTable_h__
diff --git a/mozilla/xpcom/ds/nsIAtom.idl b/mozilla/xpcom/ds/nsIAtom.idl
index 8605231f340..5b42bb389fc 100644
--- a/mozilla/xpcom/ds/nsIAtom.idl
+++ b/mozilla/xpcom/ds/nsIAtom.idl
@@ -27,9 +27,16 @@ interface nsISizeOfHandler;
%{C++
#include "nsAWritableString.h"
+#include "nsCOMPtr.h"
%}
[ref] native nsStringRef(nsAWritableString);
+/*
+ * Should this really be scriptable? Using atoms from script or proxies
+ * could be dangerous since double-wrapping could lead to loss of
+ * pointer identity.
+ */
+
[scriptable, uuid(3d1b15b0-93b4-11d1-895b-006008911b81)]
interface nsIAtom : nsISupports
{
@@ -51,23 +58,57 @@ interface nsIAtom : nsISupports
%{C++
+/*
+ * The three forms of NS_NewAtom and do_GetAtom (for use with
+ * |nsCOMPtr|) return the atom for the string given. At any
+ * given time there will always be one atom representing a given string.
+ * Atoms are intended to make string comparison cheaper by simplifying
+ * it to pointer equality. A pointer to the atom that does not own a
+ * reference is not guaranteed to be valid.
+ *
+ * The three forms of NS_NewPermanentAtom and do_GetPermanentAtom return
+ * the atom for the given string and ensure that the atom is permanent.
+ * An atom that is permanent will exist (occupy space at a specific
+ * location in memory) until XPCOM is shut down. The advantage of
+ * permanent atoms is that they do not need to maintain a reference
+ * count, which requires locking and hurts performance.
+ */
+
/**
- * Find an atom that matches the given iso-latin1 C string. The
- * C string is translated into it's unicode equivalent.
+ * Find an atom that matches the given ISO-Latin1 C string. The
+ * C string is translated into its unicode equivalent.
*/
extern NS_COM nsIAtom* NS_NewAtom(const char* isolatin1);
+extern NS_COM nsIAtom* NS_NewPermanentAtom(const char* isolatin1);
+
+inline already_AddRefed do_GetAtom(const char* isolatin1)
+ { return NS_NewAtom(isolatin1); }
+inline already_AddRefed do_GetPermanentAtom(const char* isolatin1)
+ { return NS_NewPermanentAtom(isolatin1); }
/**
* Find an atom that matches the given unicode string. The string is assumed
* to be zero terminated.
*/
extern NS_COM nsIAtom* NS_NewAtom(const PRUnichar* unicode);
+extern NS_COM nsIAtom* NS_NewPermanentAtom(const PRUnichar* unicode);
+
+inline already_AddRefed do_GetAtom(const PRUnichar* unicode)
+ { return NS_NewAtom(unicode); }
+inline already_AddRefed do_GetPermanentAtom(const PRUnichar* unicode)
+ { return NS_NewPermanentAtom(unicode); }
/**
* Find an atom that matches the given string.
*/
extern NS_COM nsIAtom* NS_NewAtom(const nsAReadableString& aString);
+extern NS_COM nsIAtom* NS_NewPermanentAtom(const nsAReadableString& aString);
+
+inline already_AddRefed do_GetAtom(const nsAReadableString& aString)
+ { return NS_NewAtom(aString); }
+inline already_AddRefed do_GetPermanentAtom(const nsAReadableString& aString)
+ { return NS_NewPermanentAtom(aString); }
/**
* Return a count of the total number of atoms currently
@@ -75,6 +116,4 @@ extern NS_COM nsIAtom* NS_NewAtom(const nsAReadableString& aString);
*/
extern NS_COM nsrefcnt NS_GetNumberOfAtoms(void);
-extern NS_COM void NS_PurgeAtomTable(void);
-
%}
diff --git a/mozilla/xpcom/ds/nsIAtomService.idl b/mozilla/xpcom/ds/nsIAtomService.idl
index 1e5cad5c06b..c655e6d78ec 100644
--- a/mozilla/xpcom/ds/nsIAtomService.idl
+++ b/mozilla/xpcom/ds/nsIAtomService.idl
@@ -50,8 +50,24 @@
#define NS_ATOMSERVICE_CLASSNAME "Atom Service"
%}
+/*
+ * Should this really be scriptable? Using atoms from script or proxies
+ * could be dangerous since double-wrapping could lead to loss of
+ * pointer identity.
+ */
[scriptable, uuid(e5d0d92b-ea45-4622-ab48-302baf2094ee)]
interface nsIAtomService : nsISupports {
+
+ /**
+ * Version of NS_NewAtom that doesn't require linking against the
+ * XPCOM library. See nsIAtom.idl.
+ */
nsIAtom getAtom(in wstring value);
+
+ /**
+ * Version of NS_NewPermanentAtom that doesn't require linking against
+ * the XPCOM library. See nsIAtom.idl.
+ */
+ nsIAtom getPermanentAtom(in wstring value);
};
diff --git a/mozilla/xpcom/tests/Makefile.in b/mozilla/xpcom/tests/Makefile.in
index 8bc5b21892e..3cca8b6344c 100644
--- a/mozilla/xpcom/tests/Makefile.in
+++ b/mozilla/xpcom/tests/Makefile.in
@@ -33,24 +33,25 @@ REQUIRES = necko \
$(NULL)
CPPSRCS = \
- nsIFileTest.cpp \
+ FilesTest.cpp \
nsIFileEnumerator.cpp \
+ nsIFileTest.cpp \
TestArray.cpp \
- TestServMgr.cpp \
- TestFactory.cpp \
+ TestAtoms.cpp \
+ TestAutoLock.cpp \
TestCallTemplates.cpp \
TestCOMPtr.cpp \
TestCOMPtrEq.cpp \
- TestID.cpp \
- TestXPIDLString.cpp \
- TestAtoms.cpp \
TestCRT.cpp \
- FilesTest.cpp \
- TestAutoLock.cpp \
+ TestFactory.cpp \
+ TestID.cpp \
TestObserverService.cpp \
+ TestPermanentAtoms.cpp \
TestPipes.cpp \
+ TestServMgr.cpp \
TestThreads.cpp \
TestVoidBTree.cpp \
+ TestXPIDLString.cpp \
$(NULL)
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
@@ -80,7 +81,10 @@ endif
include $(topsrcdir)/config/rules.mk
DEFINES += -DUSE_NSREG
-INCLUDES += -I$(srcdir)/../public -I$(srcdir)/services
+INCLUDES += \
+ -I$(srcdir)/../ds \
+ -I$(srcdir)/services \
+ $(NULL)
install::
$(INSTALL) $(srcdir)/test.properties $(DIST)/bin/res
diff --git a/mozilla/xpcom/tests/TestPermanentAtoms.cpp b/mozilla/xpcom/tests/TestPermanentAtoms.cpp
new file mode 100644
index 00000000000..8293b061a4a
--- /dev/null
+++ b/mozilla/xpcom/tests/TestPermanentAtoms.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+// vim:cindent:ts=8:et:sw=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 TestPermanentAtoms.cpp.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * L. David Baron (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIAtom.h"
+#include "nsAtomTable.h"
+#include "nsCOMPtr.h"
+#include
+#include "nsString.h"
+#include "nsReadableUtils.h"
+
+static void Assert(PRBool aCondition, const char* aStatement)
+{
+ printf("%s: %s\n", aCondition?"PASS":"FAIL", aStatement);
+}
+
+static void AssertString(nsIAtom *aAtom, const nsAString& aString)
+{
+ const PRUnichar *str;
+ NS_STATIC_CAST(AtomImpl*,aAtom)->GetUnicode(&str);
+ Assert(nsDependentString(str) == aString, "string is correct");
+}
+
+static void AssertPermanence(nsIAtom *aAtom, PRBool aPermanence)
+{
+ Assert(NS_STATIC_CAST(AtomImpl*,aAtom)->IsPermanent() == aPermanence,
+ aPermanence ? "atom is permanent" : "atom is not permanent");
+}
+
+int main()
+{
+ nsCOMPtr foo = do_GetAtom("foo");
+ AssertString(foo, NS_LITERAL_STRING("foo"));
+ AssertPermanence(foo, PR_FALSE);
+
+ nsCOMPtr foop = do_GetPermanentAtom("foo");
+ AssertString(foop, NS_LITERAL_STRING("foo"));
+ AssertPermanence(foop, PR_TRUE);
+
+ Assert(foo == foop, "atoms are equal");
+
+ nsCOMPtr barp = do_GetPermanentAtom("bar");
+ AssertString(barp, NS_LITERAL_STRING("bar"));
+ AssertPermanence(barp, PR_TRUE);
+
+ nsCOMPtr bar = do_GetAtom("bar");
+ AssertString(bar, NS_LITERAL_STRING("bar"));
+ AssertPermanence(bar, PR_TRUE);
+
+ Assert(bar == barp, "atoms are equal");
+
+ return 0;
+}
diff --git a/mozilla/xpcom/tests/makefile.win b/mozilla/xpcom/tests/makefile.win
index 52770189296..1eb2f01ad52 100644
--- a/mozilla/xpcom/tests/makefile.win
+++ b/mozilla/xpcom/tests/makefile.win
@@ -51,6 +51,7 @@ PROG19 = .\$(OBJDIR)\TestVoidBTree.exe
PROG20 = .\$(OBJDIR)\nsIFileEnumerator.exe
PROG21 = .\$(OBJDIR)\TestCOMPtrEq.exe
PROG22 = .\$(OBJDIR)\TestCallTemplates.exe
+PROG23 = .\$(OBJDIR)\TestPermanentAtoms.exe
RESFILE = timer.res
@@ -74,6 +75,7 @@ PROGRAMS = $(PROG1) \
$(PROG20) \
$(PROG21) \
$(PROG22) \
+ $(PROG23) \
$(NULL)
LCFLAGS=-DUSE_NSREG -GX
@@ -81,7 +83,8 @@ LCFLAGS=-DUSE_NSREG -GX
LINCS= \
-Iservices \
- $(NULL)
+ -I..\ds \
+ $(NULL)
LLIBS= \
$(DIST)\lib\xpcom.lib \
@@ -115,5 +118,6 @@ $(PROG19): $(OBJDIR) TestVoidBTree.cpp
$(PROG20): $(OBJDIR) nsIFileEnumerator.cpp
$(PROG21): $(OBJDIR) TestCOMPtrEq.cpp
$(PROG22): $(OBJDIR) TestCallTemplates.cpp
+$(PROG23): $(OBJDIR) TestPermanentAtoms.cpp