1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
8 * Implementation details of the atoms table.
11 #ifndef vm_AtomsTable_h
12 #define vm_AtomsTable_h
14 #include "gc/Barrier.h"
15 #include "js/GCHashTable.h"
16 #include "js/TypeDecls.h"
17 #include "js/Vector.h"
18 #include "vm/StringType.h"
21 * The atoms table is a mapping from strings to JSAtoms that supports
22 * incremental sweeping.
29 static inline HashNumber
hash(const Lookup
& l
);
30 static MOZ_ALWAYS_INLINE
bool match(const WeakHeapPtr
<JSAtom
*>& entry
,
31 const Lookup
& lookup
);
32 static void rekey(WeakHeapPtr
<JSAtom
*>& k
,
33 const WeakHeapPtr
<JSAtom
*>& newKey
) {
38 struct js::AtomHasher::Lookup
{
40 const JS::Latin1Char
* latin1Chars
;
41 const char16_t
* twoByteChars
;
42 const char* utf8Bytes
;
44 enum { TwoByteChar
, Latin1
, UTF8
} type
;
47 const JSAtom
* atom
; /* Optional. */
48 JS::AutoCheckCannotGC nogc
;
52 MOZ_ALWAYS_INLINE
Lookup(const char* utf8Bytes
, size_t byteLen
, size_t length
,
54 : utf8Bytes(utf8Bytes
),
61 MOZ_ALWAYS_INLINE
Lookup(const char16_t
* chars
, size_t length
)
62 : twoByteChars(chars
),
66 hash(mozilla::HashString(chars
, length
)) {}
68 MOZ_ALWAYS_INLINE
Lookup(const JS::Latin1Char
* chars
, size_t length
)
73 hash(mozilla::HashString(chars
, length
)) {}
75 MOZ_ALWAYS_INLINE
Lookup(HashNumber hash
, const char16_t
* chars
,
77 : twoByteChars(chars
),
82 MOZ_ASSERT(hash
== mozilla::HashString(chars
, length
));
85 MOZ_ALWAYS_INLINE
Lookup(HashNumber hash
, const JS::Latin1Char
* chars
,
92 MOZ_ASSERT(hash
== mozilla::HashString(chars
, length
));
95 inline explicit Lookup(const JSAtom
* atom
)
96 : type(atom
->hasLatin1Chars() ? Latin1
: TwoByteChar
),
97 length(atom
->length()),
100 if (type
== Latin1
) {
101 latin1Chars
= atom
->latin1Chars(nogc
);
102 MOZ_ASSERT(mozilla::HashString(latin1Chars
, length
) == hash
);
104 MOZ_ASSERT(type
== TwoByteChar
);
105 twoByteChars
= atom
->twoByteChars(nogc
);
106 MOZ_ASSERT(mozilla::HashString(twoByteChars
, length
) == hash
);
110 // Return: true iff the string in |atom| matches the string in this Lookup.
111 bool StringsMatch(const JSAtom
& atom
) const;
114 // Note: Use a 'class' here to make forward declarations easier to use.
115 class AtomSet
: public JS::GCHashSet
<WeakHeapPtr
<JSAtom
*>, AtomHasher
,
118 JS::GCHashSet
<WeakHeapPtr
<JSAtom
*>, AtomHasher
, SystemAllocPolicy
>;
122 explicit AtomSet(size_t length
) : Base(length
) {};
125 // This class is a wrapper for AtomSet that is used to ensure the AtomSet is
126 // not modified. It should only expose read-only methods from AtomSet.
127 // Note however that the atoms within the table can be marked during GC.
128 class FrozenAtomSet
{
132 // This constructor takes ownership of the passed-in AtomSet.
133 explicit FrozenAtomSet(AtomSet
* set
) { mSet
= set
; }
135 ~FrozenAtomSet() { js_delete(mSet
); }
137 MOZ_ALWAYS_INLINE
AtomSet::Ptr
readonlyThreadsafeLookup(
138 const AtomSet::Lookup
& l
) const;
140 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
141 return mSet
->shallowSizeOfIncludingThis(mallocSizeOf
);
144 using Range
= AtomSet::Range
;
146 AtomSet::Range
all() const { return mSet
->all(); }
150 // Use a low initial capacity for atom hash tables to avoid penalizing
151 // runtimes which create a small number of atoms.
152 static const size_t InitialTableSize
= 16;
154 // The main atoms set.
157 // Set of atoms added while the |atoms| set is being swept.
158 AtomSet
* atomsAddedWhileSweeping
;
160 // List of pinned atoms that are traced in every GC.
161 Vector
<JSAtom
*, 0, SystemAllocPolicy
> pinnedAtoms
;
164 // An iterator used for sweeping atoms incrementally.
165 using SweepIterator
= AtomSet::Enum
;
171 template <typename CharT
>
172 MOZ_ALWAYS_INLINE JSAtom
* atomizeAndCopyCharsNonStaticValidLength(
173 JSContext
* cx
, const CharT
* chars
, size_t length
,
174 const mozilla::Maybe
<uint32_t>& indexValue
,
175 const AtomHasher::Lookup
& lookup
);
177 bool maybePinExistingAtom(JSContext
* cx
, JSAtom
* atom
);
179 void tracePinnedAtoms(JSTracer
* trc
);
181 // Sweep all atoms non-incrementally.
182 void traceWeak(JSTracer
* trc
);
184 bool startIncrementalSweep(mozilla::Maybe
<SweepIterator
>& atomsToSweepOut
);
186 // Sweep some atoms incrementally and return whether we finished.
187 bool sweepIncrementally(SweepIterator
& atomsToSweep
, JS::SliceBudget
& budget
);
189 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
192 void mergeAtomsAddedWhileSweeping();
195 bool AtomIsPinned(JSContext
* cx
, JSAtom
* atom
);
199 #endif /* vm_AtomsTable_h */