nsAtomTable.cpp revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
// vim:cindent:ts=2:et:sw=2:
/* ***** 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
*
* 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 ***** */
#include "nsAtomTable.h"
#include "nsStaticAtom.h"
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsCRT.h"
#include "pldhash.h"
#include "prenv.h"
#include "nsVoidArray.h"
#define PL_ARENA_CONST_ALIGN_MASK 3
#include "plarena.h"
class nsStaticAtomWrapper;
/**
* 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.ops| is 0, then the table is uninitialized.
*/
static PLDHashTable gAtomTable;
// this is where we keep the nsStaticAtomWrapper objects
static PLArenaPool* gStaticAtomArena = 0;
class nsStaticAtomWrapper : public nsIAtom
{
public:
{
}
~nsStaticAtomWrapper() { // no subclasses -> not virtual
// this is arena allocated and won't be called except in debug
// builds. If this function ever does anything non-debug, be sure
// to get rid of the ifdefs in AtomTableClearEntry!
}
void** aInstancePtr);
const nsStaticAtom* GetStaticAtom() {
return mStaticAtom;
}
private:
const nsStaticAtom* mStaticAtom;
};
// the atomtableentry can contain either an AtomImpl or a
// nsStaticAtomWrapper, indicated by the first bit of PtrBits
typedef unsigned long PtrBits;
struct AtomTableEntry : public PLDHashEntryHdr {
// mAtom & 0x1 means (mAtom & ~0x1) points to an nsStaticAtomWrapper
// else it points to an nsAtomImpl
inline PRBool IsStaticAtom() const {
return (mAtom & 0x1) != 0;
}
}
"Pointers must align or this is broken");
}
inline void ClearAtom() {
}
return (mAtom & ~0x1) != 0;
}
// these accessors assume that you already know the type
inline AtomImpl *GetAtomImpl() const {
}
inline nsStaticAtomWrapper *GetStaticAtomWrapper() const {
}
inline const nsStaticAtom* GetStaticAtom() const {
return GetStaticAtomWrapper()->GetStaticAtom();
}
// type-agnostic accessors
// get the string buffer
inline const char* get() const {
}
// get an addreffed nsIAtom - not using already_AddRef'ed atom
// because the callers are not (and should not be) using nsCOMPtr
if (IsStaticAtom())
else {
result = GetAtomImpl();
}
return result;
}
};
PR_STATIC_CALLBACK(const void *)
{
}
const PLDHashEntryHdr *entry,
const void *key)
{
}
PR_STATIC_CALLBACK(void)
{
if (!he->IsStaticAtom()) {
// 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())
}
else {
}
}
static const PLDHashTableOps AtomTableOps = {
};
#ifdef DEBUG
{
if (entry->IsStaticAtom())
return PL_DHASH_NEXT;
if (!atom->IsPermanent()) {
const char *str;
}
return PL_DHASH_NEXT;
}
#endif
static inline
{
#ifdef NS_BUILD_REFCNT_LOGGING
{
do {
} while (refcount);
}
#endif
}
void NS_PurgeAtomTable()
{
if (gAtomTable.ops) {
#ifdef DEBUG
if (PR_GetEnv("MOZ_DUMP_ATOM_LEAKS")) {
printf("*** %d atoms still exist (including permanent):\n",
}
#endif
gAtomTable.entryCount = 0;
if (gStaticAtomArena) {
delete gStaticAtomArena;
}
}
}
{
}
{
// 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()) {
if (gAtomTable.entryCount == 0) {
"PL_DHashTableFinish changed the entry count");
}
}
}
{
return 2;
}
{
return 1;
}
/* virtual */ PRBool
{
return PR_FALSE;
}
/* virtual */ PRBool
{
return PR_TRUE;
}
{
/*
Note: since the |size| will initially also include the |PRUnichar| member
|mString|, our size calculation will give us one character too many.
We use that extra character for a zero-terminator.
Note: this construction is not guaranteed to be possible by the C++
compiler. A more reliable scheme is used by |nsShared[C]String|s, see
*/
return ii;
}
"converting atom that's already permanent");
// Just let the constructor overwrite the vtable pointer.
return aAtom;
}
{
return NS_OK;
}
{
return NS_OK;
}
{
return NS_OK;
}
{
return NS_OK;
}
{
return NS_OK;
}
//----------------------------------------------------------------------
// wrapper class for the nsStaticAtom struct
{
return 2;
}
{
return 1;
}
{
return NS_OK;
}
{
// static should always be always ASCII, to allow tools like gperf
// to generate the tables, and to avoid unnecessary conversion
"Data loss - atom should be ASCII");
return NS_OK;
}
{
return NS_OK;
}
{
return NS_OK;
}
{
return NS_OK;
}
//----------------------------------------------------------------------
{
}
{
}
static nsStaticAtomWrapper*
{
if (!gStaticAtomArena) {
gStaticAtomArena = new PLArenaPool;
if (!gStaticAtomArena)
return nsnull;
}
void* mem;
return wrapper;
}
{
if (!gAtomTable.ops &&
sizeof(AtomTableEntry), 2048)) {
return nsnull;
}
return NS_STATIC_CAST(AtomTableEntry*,
PL_DHASH_ADD));
}
{
// this does two things:
// 1) wraps each static atom in a wrapper, if necessary
// 2) initializes the address pointed to by each mAtom slot
for (PRUint32 i=0; i<aAtomCount; i++) {
"Static atoms must be ASCII!");
AtomTableEntry *he =
// there already is an atom with this name in the table.. but we
// still have to update mAtom
// since we wanted to create a static atom but there is
// already one there, we convert it to a non-refcounting
// permanent atom
}
// and now, if the consumer wants to remember this value in a
// slot, we do so
}
else {
// but even if atom is null, no real difference in code..
}
}
return NS_OK;
}
{
return NS_NewAtom(utf8String);
}
{
if (!atom) {
return nsnull;
}
return atom;
}
{
}
{
return he->GetStaticAtomWrapper();
// either there is no atom and we'll create an AtomImpl,
// or there is an existing AtomImpl
if (atom) {
// ensure that it's permanent
if (!atom->IsPermanent()) {
}
} else {
// otherwise, make a new atom
if ( !atom ) {
return nsnull;
}
}
return atom;
}
{
}
{
}
{
return gAtomTable.entryCount;
}