Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/nsGkAtoms.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 nsGkAtoms_h___
8
#define nsGkAtoms_h___
9
10
#include "nsAtom.h"
11
12
// Static atoms are structured carefully to satisfy a lot of constraints.
13
//
14
// - We have ~2300 static atoms.
15
//
16
// - We want them to be constexpr so they end up in .rodata, and thus shared
17
//   between processes, minimizing memory usage.
18
//
19
// - We need them to be in an array, so we can iterate over them (for
20
//   registration and lookups).
21
//
22
// - Each static atom has a string literal associated with it. We can't use a
23
//   pointer to the string literal because then the atoms won't end up in
24
//   .rodata. Therefore the string literals and the atoms must be arranged in a
25
//   way such that a numeric index can be used instead. This numeric index
26
//   (nsStaticAtom::mStringOffset) must be computable at compile-time to keep
27
//   the static atom constexpr. It should also not be too large (a uint32_t is
28
//   reasonable).
29
//
30
// - Each static atom stores the hash value of its associated string literal;
31
//   it's used in various ways. The hash value must be computed at
32
//   compile-time, to keep the static atom constexpr.
33
//
34
// - As well as accessing each static atom via array indexing, we need an
35
//   individual pointer, e.g. nsGkAtoms::foo. Ideally this would be constexpr
36
//   so it doesn't take up any space in memory. Unfortunately MSVC's constexpr
37
//   support is buggy and so this isn't possible yet. See bug 1449787.
38
//
39
// - The array of static atoms can't be in a .h file, because it's a huge
40
//   constexpr expression, which would blow out compile times. But the
41
//   individual pointers for the static atoms must be in a .h file so they are
42
//   public.
43
//
44
// nsGkAtoms below defines static atoms in a way that satisfies these
45
// constraints. It uses nsGkAtomList.h, which defines the names and values of
46
// the atoms.
47
//
48
// nsGkAtomList.h is generated by StaticAtoms.py and has entries that look
49
// like this:
50
//
51
//   GK_ATOM(one, "one", 0x01234567, nsStaticAtom, Atom)
52
//   GK_ATOM(two, "two", 0x12345678, nsICSSPseudoElement, PseudoElementAtom)
53
//   GK_ATOM(three, "three", 0x23456789, nsICSSAnonBoxPseudo, InheritingAnonBoxAtom)
54
//
55
// After macro expansion, the atom definitions look like the following:
56
//
57
//   ====> nsGkAtoms.h <====
58
//
59
//   namespace mozilla {
60
//   namespace detail {
61
//
62
//   struct GkAtoms
63
//   {
64
//     // The declaration of each atom's string.
65
//     const char16_t one_string[sizeof("one")];
66
//     const char16_t two_string[sizeof("two")];
67
//     const char16_t three_string[sizeof("three")];
68
//
69
//     // The enum value for each atom.
70
//     enum class Atoms {
71
//       one_,
72
//       two_,
73
//       three_,
74
//       AtomsCount
75
//     };
76
//
77
//     const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
78
//   };
79
//
80
//   } // namespace detail
81
//   } // namespace mozilla
82
//
83
//   // This class holds the pointers to the individual atoms.
84
//   class nsGkAtoms
85
//   {
86
//   private:
87
//     // This is a useful handle to the array of atoms, used below and also
88
//     // possibly by Rust code.
89
//     static const nsStaticAtom* const sAtoms;
90
//
91
//     // The number of atoms, used below.
92
//     static constexpr size_t sAtomsLen =
93
//       static_cast<size_t>(detail::MyAtoms::Atoms::AtomsCount);
94
//
95
//   public:
96
//     // These types are not `nsStaticAtom* const`, etc. -- even though these
97
//     // atoms are immutable -- because they are often passed to functions with
98
//     // `nsAtom*` parameters, i.e. that can be passed both dynamic and
99
//     // static.
100
//     static nsStaticAtom* one;
101
//     static nsICSSPseudoElement* two;
102
//     static nsICSSAnonBoxPseudo* three;
103
//   };
104
//
105
//   ====> nsGkAtoms.cpp <====
106
//
107
//   namespace mozilla {
108
//   namespace detail {
109
//
110
//   // Need to suppress some MSVC warning weirdness with WrappingMultiply().
111
//   MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
112
//   // Because this is `constexpr` it ends up in read-only memory where it can
113
//   // be shared between processes.
114
//   static constexpr GkAtoms gGkAtoms = {
115
//     // The initialization of each atom's string.
116
//     u"one",
117
//     u"two",
118
//     u"three",
119
//     {
120
//       // The initialization of the atoms themselves.
121
//       nsStaticAtom(
122
//         u"one", 3,
123
//         0x01234567,
124
//         offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::one)]) -
125
//         offsetof(GkAtoms, one_string)),
126
//       nsStaticAtom(
127
//         u"two", 3,
128
//         0x12345678,
129
//         offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::two)]) -
130
//         offsetof(GkAtoms, two_string)),
131
//       nsStaticAtom(
132
//         u"three", 3,
133
//         0x23456789,
134
//         offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::three)]) -
135
//         offsetof(GkAtoms, three_string)),
136
//     }
137
//   };
138
//   MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
139
//
140
//   } // namespace detail
141
//   } // namespace mozilla
142
//
143
//   const nsStaticAtom* const nsGkAtoms::sAtoms =
144
//     mozilla::detail::gGkAtoms.mAtoms;
145
//
146
//   // Definition of the pointer to the static atom.
147
//   nsStaticAtom* nsGkAtoms::one =
148
//     const_cast<nsStaticAtom*>(static_cast<const nsStaticAtom*>(
149
//       &detail::gGkAtoms.mAtoms[
150
//         static_cast<size_t>(detail::GkAtoms::Atoms::one)]);
151
//   nsICSSPseudoElement* nsGkAtoms::two =
152
//     const_cast<nsICSSPseudoElement*>(static_cast<const nsICSSPseudoElement*>(
153
//       &detail::gGkAtoms.mAtoms[
154
//         static_cast<size_t>(detail::GkAtoms::Atoms::two)]);
155
//   nsICSSAnonBoxPseudo* nsGkAtoms::three =
156
//     const_cast<nsICSSAnonBoxPseudo*>(static_cast<const nsICSSAnonBoxPseudo*>(
157
//       &detail::gGkAtoms.mAtoms[
158
//         static_cast<size_t>(detail::GkAtoms::Atoms::three)]);
159
160
// Trivial subclasses of nsStaticAtom so that function signatures can require
161
// an atom from a specific atom list.
162
#define DEFINE_STATIC_ATOM_SUBCLASS(name_)                   \
163
  class name_ : public nsStaticAtom                          \
164
  {                                                          \
165
  public:                                                    \
166
    constexpr name_(const char16_t* aStr, uint32_t aLength,  \
167
                    uint32_t aHash, uint32_t aOffset)        \
168
0
      : nsStaticAtom(aStr, aLength, aHash, aOffset) {}       \
Unexecuted instantiation: nsICSSAnonBoxPseudo::nsICSSAnonBoxPseudo(char16_t const*, unsigned int, unsigned int, unsigned int)
Unexecuted instantiation: nsICSSPseudoElement::nsICSSPseudoElement(char16_t const*, unsigned int, unsigned int, unsigned int)
169
  };
170
171
DEFINE_STATIC_ATOM_SUBCLASS(nsICSSAnonBoxPseudo)
172
DEFINE_STATIC_ATOM_SUBCLASS(nsICSSPseudoElement)
173
174
#undef DEFINE_STATIC_ATOM_SUBCLASS
175
176
namespace mozilla {
177
namespace detail {
178
179
// This `detail` class contains the atom strings and the atom objects.
180
// Because they are together in a class, the mStringOffset field of the
181
// atoms will be small and can be initialized at compile time.
182
//
183
// A `detail` namespace is used because the things within it aren't directly
184
// referenced by external users of these static atoms.
185
struct GkAtoms
186
{
187
  // The declaration of each atom's string.
188
  #define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
189
    const char16_t name_##_string[sizeof(value_)];
190
  #include "nsGkAtomList.h"
191
  #undef GK_ATOM
192
193
  // The enum value for each atom.
194
  enum class Atoms {
195
    #define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
196
      name_,
197
    #include "nsGkAtomList.h"
198
    #undef GK_ATOM
199
    AtomsCount
200
  };
201
202
  const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
203
};
204
205
} // namespace detail
206
} // namespace mozilla
207
208
class nsGkAtoms
209
{
210
private:
211
  static const nsStaticAtom* const sAtoms;
212
  static constexpr size_t sAtomsLen =
213
    static_cast<size_t>(mozilla::detail::GkAtoms::Atoms::AtomsCount);
214
215
public:
216
  static void RegisterStaticAtoms();
217
218
  static nsStaticAtom* GetAtomByIndex(size_t aIndex)
219
0
  {
220
0
    MOZ_ASSERT(aIndex < sAtomsLen);
221
0
    return const_cast<nsStaticAtom*>(&sAtoms[aIndex]);
222
0
  }
223
224
  // The declaration of the pointer to each static atom.
225
  //
226
  // XXX: Eventually this should be combined with its definition and the
227
  // pointer should be made `constexpr`. See bug 1449787.
228
  #define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
229
    static type_* name_;
230
  #include "nsGkAtomList.h"
231
  #undef GK_ATOM
232
};
233
234
#endif /* nsGkAtoms_h___ */