Reduce the performance cost of (threadsafely) refcounting many atoms by creating a second implementation of nsIAtom (derived from the first) that does not refcount and gets destroyed at XPCOM shutdown. Normal atoms are converted to permanent ones without loss of pointer identity when a permanent atom is requested and a normal one already exists. b=92141 r=waterson sr=brendan

This commit is contained in:
dbaron%fas.harvard.edu 2001-10-20 23:19:07 +00:00
Родитель dc61ae1b36
Коммит 2d95ccc700
18 изменённых файлов: 417 добавлений и 270 удалений

Просмотреть файл

@ -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
}

Просмотреть файл

@ -1,68 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCSSAtoms.h"
// define storage for all atoms
#define CSS_ATOM(_name, _value) nsIAtom* nsCSSAtoms::_name;
#include "nsCSSAtomList.h"
#undef CSS_ATOM
static nsrefcnt gRefCnt;
void nsCSSAtoms::AddRefAtoms()
{
if (0 == gRefCnt++) {
// create atoms
#define CSS_ATOM(_name, _value) _name = NS_NewAtom(_value);
#include "nsCSSAtomList.h"
#undef CSS_ATOM
}
}
void nsCSSAtoms::ReleaseAtoms()
{
NS_PRECONDITION(gRefCnt != 0, "bad release atoms");
if (--gRefCnt == 0) {
// release atoms
#define CSS_ATOM(_name, _value) NS_RELEASE(_name);
#include "nsCSSAtomList.h"
#undef CSS_ATOM
}
}

Просмотреть файл

@ -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
}

Просмотреть файл

@ -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
}

Просмотреть файл

@ -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
}

Просмотреть файл

@ -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
}

Просмотреть файл

@ -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
}

Просмотреть файл

@ -1,96 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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):
* Original Author: Rod Spears (rods@netscape.com)
*
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsString.h"
#include "nsINameSpaceManager.h"
#include "nsSVGAtoms.h"
#include "nsLayoutCID.h"
static const char kSVGNameSpace[] = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.svg";
PRInt32 nsSVGAtoms::nameSpaceID;
// define storage for all atoms
#define SVG_ATOM(_name, _value) nsIAtom* nsSVGAtoms::_name;
#include "nsSVGAtomList.h"
#undef SVG_ATOM
static nsrefcnt gRefCnt = 0;
static nsINameSpaceManager* gNameSpaceManager;
void nsSVGAtoms::AddRefAtoms() {
if (gRefCnt == 0) {
/* SVG Atoms registers the SVG name space ID because it's a convenient
place to do this, if you don't want a permanent, "well-known" ID.
*/
NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
nsCOMPtr<nsINameSpaceManager> nsmgr =
do_CreateInstance(kNameSpaceManagerCID);
if (nsmgr) {
nsmgr->RegisterNameSpace(NS_ConvertASCIItoUCS2(kSVGNameSpace),
nameSpaceID);
gNameSpaceManager = nsmgr;
NS_ADDREF(gNameSpaceManager);
} else {
NS_ASSERTION(0, "failed to create SVG atoms namespace manager");
}
// now register the atoms
#define SVG_ATOM(_name, _value) _name = NS_NewAtom(_value);
#include "nsSVGAtomList.h"
#undef SVG_ATOM
}
++gRefCnt;
}
void nsSVGAtoms::ReleaseAtoms() {
NS_PRECONDITION(gRefCnt != 0, "bad release of SVG atoms");
if (--gRefCnt == 0) {
#define SVG_ATOM(_name, _value) NS_RELEASE(_name);
#include "nsSVGAtomList.h"
#undef SVG_ATOM
NS_IF_RELEASE(gNameSpaceManager);
}
}

Просмотреть файл

@ -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
}

Просмотреть файл

@ -89,6 +89,7 @@
#include "nsFastLoadService.h"
#include "nsAtomService.h"
#include "nsAtomTable.h"
#include "nsTraceRefcnt.h"
#include "nsTimelineService.h"

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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<PRUnichar> 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;
}

Просмотреть файл

@ -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__

Просмотреть файл

@ -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<nsIAtom>|) 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<nsIAtom> do_GetAtom(const char* isolatin1)
{ return NS_NewAtom(isolatin1); }
inline already_AddRefed<nsIAtom> 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<nsIAtom> do_GetAtom(const PRUnichar* unicode)
{ return NS_NewAtom(unicode); }
inline already_AddRefed<nsIAtom> 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<nsIAtom> do_GetAtom(const nsAReadableString& aString)
{ return NS_NewAtom(aString); }
inline already_AddRefed<nsIAtom> 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);
%}

Просмотреть файл

@ -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);
};

Просмотреть файл

@ -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

Просмотреть файл

@ -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 <dbaron@fas.harvard.edu> (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 <stdio.h>
#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<nsIAtom> foo = do_GetAtom("foo");
AssertString(foo, NS_LITERAL_STRING("foo"));
AssertPermanence(foo, PR_FALSE);
nsCOMPtr<nsIAtom> foop = do_GetPermanentAtom("foo");
AssertString(foop, NS_LITERAL_STRING("foo"));
AssertPermanence(foop, PR_TRUE);
Assert(foo == foop, "atoms are equal");
nsCOMPtr<nsIAtom> barp = do_GetPermanentAtom("bar");
AssertString(barp, NS_LITERAL_STRING("bar"));
AssertPermanence(barp, PR_TRUE);
nsCOMPtr<nsIAtom> bar = do_GetAtom("bar");
AssertString(bar, NS_LITERAL_STRING("bar"));
AssertPermanence(bar, PR_TRUE);
Assert(bar == barp, "atoms are equal");
return 0;
}

Просмотреть файл

@ -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