xpcom/ds/nsAtomTable.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:626d2ef6820f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:cindent:ts=2:et:sw=2:
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/Assertions.h"
8 #include "mozilla/Attributes.h"
9 #include "mozilla/Compiler.h"
10 #include "mozilla/HashFunctions.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "mozilla/DebugOnly.h"
13 #include "mozilla/unused.h"
14
15 #include "nsAtomTable.h"
16 #include "nsStaticAtom.h"
17 #include "nsString.h"
18 #include "nsCRT.h"
19 #include "pldhash.h"
20 #include "prenv.h"
21 #include "nsThreadUtils.h"
22 #include "nsDataHashtable.h"
23 #include "nsHashKeys.h"
24 #include "nsAutoPtr.h"
25 #include "nsUnicharUtils.h"
26
27 using namespace mozilla;
28
29 #if defined(__clang__)
30 # pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
31 #elif MOZ_IS_GCC
32 # if MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
33 # pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
34 # endif
35 #endif
36
37 /**
38 * The shared hash table for atom lookups.
39 *
40 * XXX This should be manipulated in a threadsafe way or we should make
41 * sure it's only manipulated from the main thread. Probably the latter
42 * is better, since the former would hurt performance.
43 *
44 * If |gAtomTable.ops| is 0, then the table is uninitialized.
45 */
46 static PLDHashTable gAtomTable;
47
48 /**
49 * A hashtable of static atoms that existed at app startup. This hashtable helps
50 * nsHtml5AtomTable.
51 */
52 static nsDataHashtable<nsStringHashKey, nsIAtom*>* gStaticAtomTable = 0;
53
54 /**
55 * Whether it is still OK to add atoms to gStaticAtomTable.
56 */
57 static bool gStaticAtomTableSealed = false;
58
59 //----------------------------------------------------------------------
60
61 /**
62 * Note that AtomImpl objects are sometimes converted into PermanentAtomImpl
63 * objects using placement new and just overwriting the vtable pointer.
64 */
65
66 class AtomImpl : public nsIAtom {
67 public:
68 AtomImpl(const nsAString& aString, uint32_t aHash);
69
70 // This is currently only used during startup when creating a permanent atom
71 // from NS_RegisterStaticAtoms
72 AtomImpl(nsStringBuffer* aData, uint32_t aLength, uint32_t aHash);
73
74 protected:
75 // This is only intended to be used when a normal atom is turned into a
76 // permanent one.
77 AtomImpl() {
78 // We can't really assert that mString is a valid nsStringBuffer string,
79 // so do the best we can do and check for some consistencies.
80 NS_ASSERTION((mLength + 1) * sizeof(char16_t) <=
81 nsStringBuffer::FromData(mString)->StorageSize() &&
82 mString[mLength] == 0,
83 "Not initialized atom");
84 }
85
86 // We don't need a virtual destructor here because PermanentAtomImpl
87 // deletions aren't handled through Release().
88 ~AtomImpl();
89
90 public:
91 NS_DECL_ISUPPORTS
92 NS_DECL_NSIATOM
93
94 enum { REFCNT_PERMANENT_SENTINEL = UINT32_MAX };
95
96 virtual bool IsPermanent();
97
98 // We can't use the virtual function in the base class destructor.
99 bool IsPermanentInDestructor() {
100 return mRefCnt == REFCNT_PERMANENT_SENTINEL;
101 }
102
103 // for |#ifdef NS_BUILD_REFCNT_LOGGING| access to reference count
104 nsrefcnt GetRefCount() { return mRefCnt; }
105
106 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
107 };
108
109 /**
110 * A non-refcounted implementation of nsIAtom.
111 */
112
113 class PermanentAtomImpl MOZ_FINAL : public AtomImpl {
114 public:
115 PermanentAtomImpl(const nsAString& aString, PLDHashNumber aKeyHash)
116 : AtomImpl(aString, aKeyHash)
117 {}
118 PermanentAtomImpl(nsStringBuffer* aData, uint32_t aLength,
119 PLDHashNumber aKeyHash)
120 : AtomImpl(aData, aLength, aKeyHash)
121 {}
122 PermanentAtomImpl()
123 {}
124
125 ~PermanentAtomImpl();
126 NS_IMETHOD_(MozExternalRefCountType) AddRef();
127 NS_IMETHOD_(MozExternalRefCountType) Release();
128
129 virtual bool IsPermanent();
130
131 // SizeOfIncludingThis() isn't needed -- the one inherited from AtomImpl is
132 // good enough, because PermanentAtomImpl doesn't add any new data members.
133
134 void* operator new(size_t size, AtomImpl* aAtom) CPP_THROW_NEW;
135 void* operator new(size_t size) CPP_THROW_NEW
136 {
137 return ::operator new(size);
138 }
139 };
140
141 //----------------------------------------------------------------------
142
143 struct AtomTableEntry : public PLDHashEntryHdr {
144 AtomImpl* mAtom;
145 };
146
147 struct AtomTableKey
148 {
149 AtomTableKey(const char16_t* aUTF16String, uint32_t aLength,
150 /*inout*/ uint32_t& aHash)
151 : mUTF16String(aUTF16String),
152 mUTF8String(nullptr),
153 mLength(aLength)
154 {
155 if (aHash) {
156 MOZ_ASSERT(aHash == HashString(mUTF16String, mLength));
157 mHash = aHash;
158 } else {
159 UpdateHashKey();
160 aHash = mHash;
161 }
162 }
163
164 AtomTableKey(const char* aUTF8String, uint32_t aLength,
165 /*inout*/ uint32_t& aHash)
166 : mUTF16String(nullptr),
167 mUTF8String(aUTF8String),
168 mLength(aLength)
169 {
170 if (aHash) {
171 mozilla::DebugOnly<bool> err;
172 MOZ_ASSERT(aHash == HashUTF8AsUTF16(mUTF8String, mLength, &err));
173 mHash = aHash;
174 } else {
175 UpdateHashKey();
176 aHash = mHash;
177 }
178 }
179
180 const char16_t* mUTF16String;
181 const char* mUTF8String;
182 uint32_t mLength;
183 uint32_t mHash;
184
185 void UpdateHashKey()
186 {
187 if (mUTF8String) {
188 bool err;
189 mHash = HashUTF8AsUTF16(mUTF8String, mLength, &err);
190 if (err) {
191 mUTF8String = nullptr;
192 mLength = 0;
193 mHash = 0;
194 }
195 } else {
196 mHash = HashString(mUTF16String, mLength);
197 }
198 }
199 };
200
201 static PLDHashNumber
202 AtomTableGetHash(PLDHashTable *table, const void *key)
203 {
204 const AtomTableKey *k = static_cast<const AtomTableKey*>(key);
205 return k->mHash;
206 }
207
208 static bool
209 AtomTableMatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
210 const void *key)
211 {
212 const AtomTableEntry *he = static_cast<const AtomTableEntry*>(entry);
213 const AtomTableKey *k = static_cast<const AtomTableKey*>(key);
214
215 if (k->mUTF8String) {
216 return
217 CompareUTF8toUTF16(nsDependentCSubstring(k->mUTF8String,
218 k->mUTF8String + k->mLength),
219 nsDependentAtomString(he->mAtom)) == 0;
220 }
221
222 uint32_t length = he->mAtom->GetLength();
223 if (length != k->mLength) {
224 return false;
225 }
226
227 return memcmp(he->mAtom->GetUTF16String(),
228 k->mUTF16String, length * sizeof(char16_t)) == 0;
229 }
230
231 static void
232 AtomTableClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
233 {
234 // Normal |AtomImpl| atoms are deleted when their refcount hits 0, and
235 // they then remove themselves from the table. In other words, they
236 // are owned by the callers who own references to them.
237 // |PermanentAtomImpl| permanent atoms ignore their refcount and are
238 // deleted when they are removed from the table at table destruction.
239 // In other words, they are owned by the atom table.
240
241 AtomImpl *atom = static_cast<AtomTableEntry*>(entry)->mAtom;
242 if (atom->IsPermanent()) {
243 // Note that the cast here is important since AtomImpls doesn't have a
244 // virtual dtor.
245 delete static_cast<PermanentAtomImpl*>(atom);
246 }
247 }
248
249 static bool
250 AtomTableInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
251 const void *key)
252 {
253 static_cast<AtomTableEntry*>(entry)->mAtom = nullptr;
254
255 return true;
256 }
257
258
259 static const PLDHashTableOps AtomTableOps = {
260 PL_DHashAllocTable,
261 PL_DHashFreeTable,
262 AtomTableGetHash,
263 AtomTableMatchKey,
264 PL_DHashMoveEntryStub,
265 AtomTableClearEntry,
266 PL_DHashFinalizeStub,
267 AtomTableInitEntry
268 };
269
270
271 #ifdef DEBUG
272 static PLDHashOperator
273 DumpAtomLeaks(PLDHashTable *table, PLDHashEntryHdr *he,
274 uint32_t index, void *arg)
275 {
276 AtomTableEntry *entry = static_cast<AtomTableEntry*>(he);
277
278 AtomImpl* atom = entry->mAtom;
279 if (!atom->IsPermanent()) {
280 ++*static_cast<uint32_t*>(arg);
281 nsAutoCString str;
282 atom->ToUTF8String(str);
283 fputs(str.get(), stdout);
284 fputs("\n", stdout);
285 }
286 return PL_DHASH_NEXT;
287 }
288 #endif
289
290 static inline
291 void PromoteToPermanent(AtomImpl* aAtom)
292 {
293 #ifdef NS_BUILD_REFCNT_LOGGING
294 {
295 nsrefcnt refcount = aAtom->GetRefCount();
296 do {
297 NS_LOG_RELEASE(aAtom, --refcount, "AtomImpl");
298 } while (refcount);
299 }
300 #endif
301 aAtom = new (aAtom) PermanentAtomImpl();
302 }
303
304 void
305 NS_PurgeAtomTable()
306 {
307 delete gStaticAtomTable;
308
309 if (gAtomTable.ops) {
310 #ifdef DEBUG
311 const char *dumpAtomLeaks = PR_GetEnv("MOZ_DUMP_ATOM_LEAKS");
312 if (dumpAtomLeaks && *dumpAtomLeaks) {
313 uint32_t leaked = 0;
314 printf("*** %d atoms still exist (including permanent):\n",
315 gAtomTable.entryCount);
316 PL_DHashTableEnumerate(&gAtomTable, DumpAtomLeaks, &leaked);
317 printf("*** %u non-permanent atoms leaked\n", leaked);
318 }
319 #endif
320 PL_DHashTableFinish(&gAtomTable);
321 gAtomTable.entryCount = 0;
322 gAtomTable.ops = nullptr;
323 }
324 }
325
326 AtomImpl::AtomImpl(const nsAString& aString, uint32_t aHash)
327 {
328 mLength = aString.Length();
329 nsRefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
330 if (buf) {
331 mString = static_cast<char16_t*>(buf->Data());
332 } else {
333 buf = nsStringBuffer::Alloc((mLength + 1) * sizeof(char16_t));
334 mString = static_cast<char16_t*>(buf->Data());
335 CopyUnicodeTo(aString, 0, mString, mLength);
336 mString[mLength] = char16_t(0);
337 }
338
339 mHash = aHash;
340 MOZ_ASSERT(mHash == HashString(mString, mLength));
341
342 NS_ASSERTION(mString[mLength] == char16_t(0), "null terminated");
343 NS_ASSERTION(buf && buf->StorageSize() >= (mLength+1) * sizeof(char16_t),
344 "enough storage");
345 NS_ASSERTION(Equals(aString), "correct data");
346
347 // Take ownership of buffer
348 mozilla::unused << buf.forget();
349 }
350
351 AtomImpl::AtomImpl(nsStringBuffer* aStringBuffer, uint32_t aLength,
352 uint32_t aHash)
353 {
354 mLength = aLength;
355 mString = static_cast<char16_t*>(aStringBuffer->Data());
356 // Technically we could currently avoid doing this addref by instead making
357 // the static atom buffers have an initial refcount of 2.
358 aStringBuffer->AddRef();
359
360 mHash = aHash;
361 MOZ_ASSERT(mHash == HashString(mString, mLength));
362
363 NS_ASSERTION(mString[mLength] == char16_t(0), "null terminated");
364 NS_ASSERTION(aStringBuffer &&
365 aStringBuffer->StorageSize() == (mLength+1) * sizeof(char16_t),
366 "correct storage");
367 }
368
369 AtomImpl::~AtomImpl()
370 {
371 NS_PRECONDITION(gAtomTable.ops, "uninitialized atom hashtable");
372 // Permanent atoms are removed from the hashtable at shutdown, and we
373 // don't want to remove them twice. See comment above in
374 // |AtomTableClearEntry|.
375 if (!IsPermanentInDestructor()) {
376 AtomTableKey key(mString, mLength, mHash);
377 PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_REMOVE);
378 if (gAtomTable.entryCount == 0) {
379 PL_DHashTableFinish(&gAtomTable);
380 NS_ASSERTION(gAtomTable.entryCount == 0,
381 "PL_DHashTableFinish changed the entry count");
382 }
383 }
384
385 nsStringBuffer::FromData(mString)->Release();
386 }
387
388 NS_IMPL_ISUPPORTS(AtomImpl, nsIAtom)
389
390 PermanentAtomImpl::~PermanentAtomImpl()
391 {
392 // So we can tell if we were permanent while running the base class dtor.
393 mRefCnt = REFCNT_PERMANENT_SENTINEL;
394 }
395
396 NS_IMETHODIMP_(MozExternalRefCountType) PermanentAtomImpl::AddRef()
397 {
398 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
399 return 2;
400 }
401
402 NS_IMETHODIMP_(MozExternalRefCountType) PermanentAtomImpl::Release()
403 {
404 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
405 return 1;
406 }
407
408 /* virtual */ bool
409 AtomImpl::IsPermanent()
410 {
411 return false;
412 }
413
414 /* virtual */ bool
415 PermanentAtomImpl::IsPermanent()
416 {
417 return true;
418 }
419
420 void* PermanentAtomImpl::operator new ( size_t size, AtomImpl* aAtom ) CPP_THROW_NEW {
421 MOZ_ASSERT(!aAtom->IsPermanent(),
422 "converting atom that's already permanent");
423
424 // Just let the constructor overwrite the vtable pointer.
425 return aAtom;
426 }
427
428 NS_IMETHODIMP
429 AtomImpl::ScriptableToString(nsAString& aBuf)
430 {
431 nsStringBuffer::FromData(mString)->ToString(mLength, aBuf);
432 return NS_OK;
433 }
434
435 NS_IMETHODIMP
436 AtomImpl::ToUTF8String(nsACString& aBuf)
437 {
438 CopyUTF16toUTF8(nsDependentString(mString, mLength), aBuf);
439 return NS_OK;
440 }
441
442 NS_IMETHODIMP_(bool)
443 AtomImpl::EqualsUTF8(const nsACString& aString)
444 {
445 return CompareUTF8toUTF16(aString,
446 nsDependentString(mString, mLength)) == 0;
447 }
448
449 NS_IMETHODIMP
450 AtomImpl::ScriptableEquals(const nsAString& aString, bool* aResult)
451 {
452 *aResult = aString.Equals(nsDependentString(mString, mLength));
453 return NS_OK;
454 }
455
456 NS_IMETHODIMP_(bool)
457 AtomImpl::IsStaticAtom()
458 {
459 return IsPermanent();
460 }
461
462 size_t
463 AtomImpl::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
464 {
465 return aMallocSizeOf(this) +
466 nsStringBuffer::FromData(mString)->
467 SizeOfIncludingThisIfUnshared(aMallocSizeOf);
468 }
469
470 //----------------------------------------------------------------------
471
472 static size_t
473 SizeOfAtomTableEntryExcludingThis(PLDHashEntryHdr *aHdr,
474 MallocSizeOf aMallocSizeOf,
475 void *aArg)
476 {
477 AtomTableEntry* entry = static_cast<AtomTableEntry*>(aHdr);
478 return entry->mAtom->SizeOfIncludingThis(aMallocSizeOf);
479 }
480
481 static size_t
482 SizeOfStaticAtomTableEntryExcludingThis(const nsAString& aKey,
483 nsIAtom* const& aData,
484 MallocSizeOf aMallocSizeOf,
485 void* aArg)
486 {
487 return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
488 }
489
490 size_t
491 NS_SizeOfAtomTablesIncludingThis(MallocSizeOf aMallocSizeOf) {
492 size_t n = 0;
493 if (gAtomTable.ops) {
494 n += PL_DHashTableSizeOfExcludingThis(&gAtomTable,
495 SizeOfAtomTableEntryExcludingThis,
496 aMallocSizeOf);
497 }
498 if (gStaticAtomTable) {
499 n += gStaticAtomTable->SizeOfIncludingThis(SizeOfStaticAtomTableEntryExcludingThis,
500 aMallocSizeOf);
501 }
502 return n;
503 }
504
505 #define ATOM_HASHTABLE_INITIAL_SIZE 4096
506
507 static inline void
508 EnsureTableExists()
509 {
510 if (!gAtomTable.ops) {
511 PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0,
512 sizeof(AtomTableEntry), ATOM_HASHTABLE_INITIAL_SIZE);
513 }
514 }
515
516 static inline AtomTableEntry*
517 GetAtomHashEntry(const char* aString, uint32_t aLength, uint32_t& aHash)
518 {
519 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
520 EnsureTableExists();
521 AtomTableKey key(aString, aLength, aHash);
522 AtomTableEntry* e =
523 static_cast<AtomTableEntry*>
524 (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
525 if (!e) {
526 NS_ABORT_OOM(gAtomTable.entryCount * gAtomTable.entrySize);
527 }
528 return e;
529 }
530
531 static inline AtomTableEntry*
532 GetAtomHashEntry(const char16_t* aString, uint32_t aLength, uint32_t& aHash)
533 {
534 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
535 EnsureTableExists();
536 AtomTableKey key(aString, aLength, aHash);
537 AtomTableEntry* e =
538 static_cast<AtomTableEntry*>
539 (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
540 if (!e) {
541 NS_ABORT_OOM(gAtomTable.entryCount * gAtomTable.entrySize);
542 }
543 return e;
544 }
545
546 class CheckStaticAtomSizes
547 {
548 CheckStaticAtomSizes() {
549 static_assert((sizeof(nsFakeStringBuffer<1>().mRefCnt) ==
550 sizeof(nsStringBuffer().mRefCount)) &&
551 (sizeof(nsFakeStringBuffer<1>().mSize) ==
552 sizeof(nsStringBuffer().mStorageSize)) &&
553 (offsetof(nsFakeStringBuffer<1>, mRefCnt) ==
554 offsetof(nsStringBuffer, mRefCount)) &&
555 (offsetof(nsFakeStringBuffer<1>, mSize) ==
556 offsetof(nsStringBuffer, mStorageSize)) &&
557 (offsetof(nsFakeStringBuffer<1>, mStringData) ==
558 sizeof(nsStringBuffer)),
559 "mocked-up strings' representations should be compatible");
560 }
561 };
562
563 nsresult
564 RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount)
565 {
566 // this does three things:
567 // 1) wraps each static atom in a wrapper, if necessary
568 // 2) initializes the address pointed to by each mBits slot
569 // 3) puts the atom into the static atom table as well
570
571 if (!gStaticAtomTable && !gStaticAtomTableSealed) {
572 gStaticAtomTable = new nsDataHashtable<nsStringHashKey, nsIAtom*>();
573 }
574
575 for (uint32_t i=0; i<aAtomCount; i++) {
576 NS_ASSERTION(nsCRT::IsAscii((char16_t*)aAtoms[i].mStringBuffer->Data()),
577 "Static atoms must be ASCII!");
578
579 uint32_t stringLen =
580 aAtoms[i].mStringBuffer->StorageSize() / sizeof(char16_t) - 1;
581
582 uint32_t hash = 0;
583 AtomTableEntry *he =
584 GetAtomHashEntry((char16_t*)aAtoms[i].mStringBuffer->Data(),
585 stringLen, hash);
586
587 if (he->mAtom) {
588 // there already is an atom with this name in the table.. but we
589 // still have to update mBits
590 if (!he->mAtom->IsPermanent()) {
591 // since we wanted to create a static atom but there is
592 // already one there, we convert it to a non-refcounting
593 // permanent atom
594 PromoteToPermanent(he->mAtom);
595 }
596
597 *aAtoms[i].mAtom = he->mAtom;
598 }
599 else {
600 AtomImpl* atom = new PermanentAtomImpl(aAtoms[i].mStringBuffer,
601 stringLen,
602 hash);
603 he->mAtom = atom;
604 *aAtoms[i].mAtom = atom;
605
606 if (!gStaticAtomTableSealed) {
607 gStaticAtomTable->Put(nsAtomString(atom), atom);
608 }
609 }
610 }
611 return NS_OK;
612 }
613
614 already_AddRefed<nsIAtom>
615 NS_NewAtom(const char* aUTF8String)
616 {
617 return NS_NewAtom(nsDependentCString(aUTF8String));
618 }
619
620 already_AddRefed<nsIAtom>
621 NS_NewAtom(const nsACString& aUTF8String)
622 {
623 uint32_t hash = 0;
624 AtomTableEntry *he = GetAtomHashEntry(aUTF8String.Data(),
625 aUTF8String.Length(),
626 hash);
627
628 if (he->mAtom) {
629 nsCOMPtr<nsIAtom> atom = he->mAtom;
630
631 return atom.forget();
632 }
633
634 // This results in an extra addref/release of the nsStringBuffer.
635 // Unfortunately there doesn't seem to be any APIs to avoid that.
636 // Actually, now there is, sort of: ForgetSharedBuffer.
637 nsString str;
638 CopyUTF8toUTF16(aUTF8String, str);
639 nsRefPtr<AtomImpl> atom = new AtomImpl(str, hash);
640
641 he->mAtom = atom;
642
643 return atom.forget();
644 }
645
646 already_AddRefed<nsIAtom>
647 NS_NewAtom(const char16_t* aUTF16String)
648 {
649 return NS_NewAtom(nsDependentString(aUTF16String));
650 }
651
652 already_AddRefed<nsIAtom>
653 NS_NewAtom(const nsAString& aUTF16String)
654 {
655 uint32_t hash = 0;
656 AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(),
657 aUTF16String.Length(),
658 hash);
659
660 if (he->mAtom) {
661 nsCOMPtr<nsIAtom> atom = he->mAtom;
662
663 return atom.forget();
664 }
665
666 nsRefPtr<AtomImpl> atom = new AtomImpl(aUTF16String, hash);
667 he->mAtom = atom;
668
669 return atom.forget();
670 }
671
672 nsIAtom*
673 NS_NewPermanentAtom(const nsAString& aUTF16String)
674 {
675 uint32_t hash = 0;
676 AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(),
677 aUTF16String.Length(),
678 hash);
679
680 AtomImpl* atom = he->mAtom;
681 if (atom) {
682 if (!atom->IsPermanent()) {
683 PromoteToPermanent(atom);
684 }
685 }
686 else {
687 atom = new PermanentAtomImpl(aUTF16String, hash);
688 he->mAtom = atom;
689 }
690
691 // No need to addref since permanent atoms aren't refcounted anyway
692 return atom;
693 }
694
695 nsrefcnt
696 NS_GetNumberOfAtoms(void)
697 {
698 return gAtomTable.entryCount;
699 }
700
701 nsIAtom*
702 NS_GetStaticAtom(const nsAString& aUTF16String)
703 {
704 NS_PRECONDITION(gStaticAtomTable, "Static atom table not created yet.");
705 NS_PRECONDITION(gStaticAtomTableSealed, "Static atom table not sealed yet.");
706 nsIAtom* atom;
707 if (!gStaticAtomTable->Get(aUTF16String, &atom)) {
708 atom = nullptr;
709 }
710 return atom;
711 }
712
713 void
714 NS_SealStaticAtomTable()
715 {
716 gStaticAtomTableSealed = true;
717 }

mercurial