Bug 1795082 - Part 2/2: Drop post-processing from getURL() r=zombie
[gecko.git] / js / src / vm / AtomsTable.h
blob55a58b92cca831bc0821676ed46178c8d219bee9
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/. */
7 /*
8 * Implementation details of the atoms table.
9 */
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.
25 namespace js {
27 struct AtomHasher {
28 struct Lookup;
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) {
34 k = newKey;
38 struct js::AtomHasher::Lookup {
39 union {
40 const JS::Latin1Char* latin1Chars;
41 const char16_t* twoByteChars;
42 const char* utf8Bytes;
44 enum { TwoByteChar, Latin1, UTF8 } type;
45 size_t length;
46 size_t byteLength;
47 const JSAtom* atom; /* Optional. */
48 JS::AutoCheckCannotGC nogc;
50 HashNumber hash;
52 MOZ_ALWAYS_INLINE Lookup(const char* utf8Bytes, size_t byteLen, size_t length,
53 HashNumber hash)
54 : utf8Bytes(utf8Bytes),
55 type(UTF8),
56 length(length),
57 byteLength(byteLen),
58 atom(nullptr),
59 hash(hash) {}
61 MOZ_ALWAYS_INLINE Lookup(const char16_t* chars, size_t length)
62 : twoByteChars(chars),
63 type(TwoByteChar),
64 length(length),
65 atom(nullptr),
66 hash(mozilla::HashString(chars, length)) {}
68 MOZ_ALWAYS_INLINE Lookup(const JS::Latin1Char* chars, size_t length)
69 : latin1Chars(chars),
70 type(Latin1),
71 length(length),
72 atom(nullptr),
73 hash(mozilla::HashString(chars, length)) {}
75 MOZ_ALWAYS_INLINE Lookup(HashNumber hash, const char16_t* chars,
76 size_t length)
77 : twoByteChars(chars),
78 type(TwoByteChar),
79 length(length),
80 atom(nullptr),
81 hash(hash) {
82 MOZ_ASSERT(hash == mozilla::HashString(chars, length));
85 MOZ_ALWAYS_INLINE Lookup(HashNumber hash, const JS::Latin1Char* chars,
86 size_t length)
87 : latin1Chars(chars),
88 type(Latin1),
89 length(length),
90 atom(nullptr),
91 hash(hash) {
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()),
98 atom(atom),
99 hash(atom->hash()) {
100 if (type == Latin1) {
101 latin1Chars = atom->latin1Chars(nogc);
102 MOZ_ASSERT(mozilla::HashString(latin1Chars, length) == hash);
103 } else {
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,
116 SystemAllocPolicy> {
117 using Base =
118 JS::GCHashSet<WeakHeapPtr<JSAtom*>, AtomHasher, SystemAllocPolicy>;
120 public:
121 AtomSet() = default;
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 {
129 AtomSet* mSet;
131 public:
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(); }
149 class AtomsTable {
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.
155 AtomSet atoms;
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;
163 public:
164 // An iterator used for sweeping atoms incrementally.
165 using SweepIterator = AtomSet::Enum;
167 AtomsTable();
168 ~AtomsTable();
169 bool init();
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;
191 private:
192 void mergeAtomsAddedWhileSweeping();
195 bool AtomIsPinned(JSContext* cx, JSAtom* atom);
197 } // namespace js
199 #endif /* vm_AtomsTable_h */