зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
dc61ae1b36
Коммит
2d95ccc700
|
@ -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
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче