Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/ds/nsAtom.h
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#ifndef nsAtom_h
8
#define nsAtom_h
9
10
#include "nsISupportsImpl.h"
11
#include "nsString.h"
12
#include "mozilla/UniquePtr.h"
13
14
namespace mozilla {
15
struct AtomsSizes;
16
}
17
18
class nsStaticAtom;
19
class nsDynamicAtom;
20
21
// This class encompasses both static and dynamic atoms.
22
//
23
// - In places where static and dynamic atoms can be used, use RefPtr<nsAtom>.
24
//   This is by far the most common case. (The exception to this is the HTML5
25
//   parser, which does its own weird thing, and uses non-refcounted dynamic
26
//   atoms.)
27
//
28
// - In places where only static atoms can appear, use nsStaticAtom* to avoid
29
//   unnecessary refcounting. This is a moderately common case.
30
//
31
// - In places where only dynamic atoms can appear, it doesn't matter much
32
//   whether you use RefPtr<nsAtom> or RefPtr<nsDynamicAtom>. This is an
33
//   extremely rare case.
34
//
35
class nsAtom
36
{
37
public:
38
  void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
39
                              mozilla::AtomsSizes& aSizes) const;
40
41
  // Dynamic HTML5 atoms are just like vanilla dynamic atoms, but we disallow
42
  // various operations, the most important of which is AddRef/Release.
43
  // XXX: we'd like to get rid of dynamic HTML5 atoms. See bug 1392185 for
44
  // details.
45
  enum class AtomKind : uint8_t {
46
    Static = 0,
47
    DynamicNormal = 1,
48
    DynamicHTML5 = 2,
49
  };
50
51
  bool Equals(char16ptr_t aString, uint32_t aLength) const
52
411
  {
53
411
    return mLength == aLength &&
54
411
           memcmp(GetUTF16String(), aString, mLength * sizeof(char16_t)) == 0;
55
411
  }
56
57
  bool Equals(const nsAString& aString) const
58
  {
59
    return Equals(aString.BeginReading(), aString.Length());
60
  }
61
62
229k
  AtomKind Kind() const { return static_cast<AtomKind>(mKind); }
63
64
229k
  bool IsStatic() const { return Kind() == AtomKind::Static; }
65
  bool IsDynamic() const
66
0
  {
67
0
    return Kind() == AtomKind::DynamicNormal ||
68
0
           Kind() == AtomKind::DynamicHTML5;
69
0
  }
70
  bool IsDynamicHTML5() const
71
  {
72
    return Kind() == AtomKind::DynamicHTML5;
73
  }
74
75
  const nsStaticAtom* AsStatic() const;
76
  const nsDynamicAtom* AsDynamic() const;
77
  nsDynamicAtom* AsDynamic();
78
79
  char16ptr_t GetUTF16String() const;
80
81
211k
  uint32_t GetLength() const { return mLength; }
82
83
  operator mozilla::Span<const char16_t>() const
84
  {
85
    return mozilla::MakeSpan(static_cast<const char16_t*>(GetUTF16String()), GetLength());
86
  }
87
88
  void ToString(nsAString& aString) const;
89
  void ToUTF8String(nsACString& aString) const;
90
91
  // A hashcode that is better distributed than the actual atom pointer, for
92
  // use in situations that need a well-distributed hashcode. It's called hash()
93
  // rather than Hash() so we can use mozilla::BloomFilter<N, nsAtom>, because
94
  // BloomFilter requires elements to implement a function called hash().
95
  //
96
  uint32_t hash() const
97
6.98k
  {
98
6.98k
    MOZ_ASSERT(!IsDynamicHTML5());
99
6.98k
    return mHash;
100
6.98k
  }
101
102
  // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
103
  // of this type is special.
104
  MozExternalRefCountType AddRef();
105
  MozExternalRefCountType Release();
106
107
  typedef mozilla::TrueType HasThreadSafeRefCnt;
108
109
protected:
110
  // Used by nsStaticAtom.
111
  constexpr nsAtom(const char16_t* aStr, uint32_t aLength, uint32_t aHash)
112
    : mLength(aLength)
113
    , mKind(static_cast<uint32_t>(nsAtom::AtomKind::Static))
114
    , mHash(aHash)
115
  {}
116
117
  // Used by nsDynamicAtom.
118
  nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash)
119
    : mLength(aString.Length())
120
    , mKind(static_cast<uint32_t>(aKind))
121
    , mHash(aHash)
122
37
  {
123
37
    MOZ_ASSERT(aKind == AtomKind::DynamicNormal ||
124
37
               aKind == AtomKind::DynamicHTML5);
125
37
  }
126
127
  ~nsAtom() = default;
128
129
  const uint32_t mLength:30;
130
  const uint32_t mKind:2; // nsAtom::AtomKind
131
  const uint32_t mHash;
132
};
133
134
// This class would be |final| if it wasn't for nsICSSAnonBoxPseudo and
135
// nsICSSPseudoElement, which are trivial subclasses used to ensure only
136
// certain static atoms are passed to certain functions.
137
class nsStaticAtom : public nsAtom
138
{
139
public:
140
  // These are deleted so it's impossible to RefPtr<nsStaticAtom>. Raw
141
  // nsStaticAtom pointers should be used instead.
142
  MozExternalRefCountType AddRef() = delete;
143
  MozExternalRefCountType Release() = delete;
144
145
  // The static atom's precomputed hash value is an argument here, but it
146
  // must be the same as would be computed by mozilla::HashString(aStr),
147
  // which is what we use when atomizing strings. We compute this hash in
148
  // Atom.py and assert in nsAtomTable::RegisterStaticAtoms that the two
149
  // hashes match.
150
  constexpr nsStaticAtom(const char16_t* aStr, uint32_t aLength,
151
                         uint32_t aHash, uint32_t aStringOffset)
152
    : nsAtom(aStr, aLength, aHash)
153
    , mStringOffset(aStringOffset)
154
  {}
155
156
  const char16_t* String() const
157
205k
  {
158
205k
    return reinterpret_cast<const char16_t*>(uintptr_t(this) - mStringOffset);
159
205k
  }
160
161
  already_AddRefed<nsAtom> ToAddRefed() {
162
    return already_AddRefed<nsAtom>(static_cast<nsAtom*>(this));
163
  }
164
165
private:
166
  // This is an offset to the string chars, which must be at a lower address in
167
  // memory.
168
  uint32_t mStringOffset;
169
};
170
171
class nsDynamicAtom : public nsAtom
172
{
173
public:
174
  // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
175
  // of this type is special.
176
  MozExternalRefCountType AddRef();
177
  MozExternalRefCountType Release();
178
179
  const char16_t* String() const
180
5.81k
  {
181
5.81k
    return reinterpret_cast<const char16_t*>(this + 1);
182
5.81k
  }
183
184
  static nsDynamicAtom* FromChars(char16_t* chars)
185
  {
186
    return reinterpret_cast<nsDynamicAtom*>(chars) - 1;
187
  }
188
189
private:
190
  friend class nsAtomTable;
191
  friend class nsAtomSubTable;
192
  // XXX: we'd like to remove nsHtml5AtomEntry. See bug 1392185.
193
  friend class nsHtml5AtomEntry;
194
195
  // These shouldn't be used directly, even by friend classes. The
196
  // Create()/Destroy() methods use them.
197
  static nsDynamicAtom* CreateInner(const nsAString& aString, uint32_t aHash);
198
  nsDynamicAtom(const nsAString& aString, uint32_t aHash);
199
0
  ~nsDynamicAtom() {}
200
201
  // Creation/destruction is done by friend classes. The first Create() is for
202
  // dynamic normal atoms, the second is for dynamic HTML5 atoms.
203
  static nsDynamicAtom* Create(const nsAString& aString, uint32_t aHash);
204
  static nsDynamicAtom* Create(const nsAString& aString);
205
  static void Destroy(nsDynamicAtom* aAtom);
206
207
  mozilla::ThreadSafeAutoRefCnt mRefCnt;
208
209
  // The atom's chars are stored at the end of the struct.
210
};
211
212
// The four forms of NS_Atomize (for use with |RefPtr<nsAtom>|) return the
213
// atom for the string given. At any given time there will always be one atom
214
// representing a given string. Atoms are intended to make string comparison
215
// cheaper by simplifying it to pointer equality. A pointer to the atom that
216
// does not own a reference is not guaranteed to be valid.
217
218
// Find an atom that matches the given UTF-8 string. The string is assumed to
219
// be zero terminated. Never returns null.
220
already_AddRefed<nsAtom> NS_Atomize(const char* aUTF8String);
221
222
// Find an atom that matches the given UTF-8 string. Never returns null.
223
already_AddRefed<nsAtom> NS_Atomize(const nsACString& aUTF8String);
224
225
// Find an atom that matches the given UTF-16 string. The string is assumed to
226
// be zero terminated. Never returns null.
227
already_AddRefed<nsAtom> NS_Atomize(const char16_t* aUTF16String);
228
229
// Find an atom that matches the given UTF-16 string. Never returns null.
230
already_AddRefed<nsAtom> NS_Atomize(const nsAString& aUTF16String);
231
232
// An optimized version of the method above for the main thread.
233
already_AddRefed<nsAtom> NS_AtomizeMainThread(const nsAString& aUTF16String);
234
235
// Return a count of the total number of atoms currently alive in the system.
236
//
237
// Note that the result is imprecise and racy if other threads are currently
238
// operating on atoms. It's also slow, since it triggers a GC before counting.
239
// Currently this function is only used in tests, which should probably remain
240
// the case.
241
nsrefcnt NS_GetNumberOfAtoms();
242
243
// Return a pointer for a static atom for the string or null if there's no
244
// static atom for this string.
245
nsStaticAtom* NS_GetStaticAtom(const nsAString& aUTF16String);
246
247
class nsAtomString : public nsString
248
{
249
public:
250
  explicit nsAtomString(const nsAtom* aAtom) { aAtom->ToString(*this); }
251
};
252
253
class nsAtomCString : public nsCString
254
{
255
public:
256
  explicit nsAtomCString(nsAtom* aAtom) { aAtom->ToUTF8String(*this); }
257
};
258
259
class nsDependentAtomString : public nsDependentString
260
{
261
public:
262
  explicit nsDependentAtomString(const nsAtom* aAtom)
263
    : nsDependentString(aAtom->GetUTF16String(), aAtom->GetLength())
264
204k
  {}
265
};
266
267
// Checks if the ascii chars in a given atom are already lowercase.
268
// If they are, no-op. Otherwise, converts all the ascii uppercase
269
// chars to lowercase and atomizes, storing the result in the inout
270
// param.
271
void ToLowerCaseASCII(RefPtr<nsAtom>& aAtom);
272
273
#endif  // nsAtom_h