88#define nsGkAtoms_h___
99
1010#include " nsAtom.h"
11- #include " nsStaticAtom.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", nsStaticAtom, Atom)
52+ // GK_ATOM(two, "two", nsICSSPseudoElement, PseudoElementAtom)
53+ // GK_ATOM(three, "three", 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+ // offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::one)]) -
124+ // offsetof(GkAtoms, one_string)),
125+ // nsStaticAtom(
126+ // u"two", 3,
127+ // offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::two)]) -
128+ // offsetof(GkAtoms, two_string)),
129+ // nsStaticAtom(
130+ // u"three", 3,
131+ // offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::three)]) -
132+ // offsetof(GkAtoms, three_string)),
133+ // }
134+ // };
135+ // MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
136+ //
137+ // } // namespace detail
138+ // } // namespace mozilla
139+ //
140+ // const nsStaticAtom* const nsGkAtoms::sAtoms =
141+ // mozilla::detail::gGkAtoms.mAtoms;
142+ //
143+ // // Definition of the pointer to the static atom.
144+ // nsStaticAtom* nsGkAtoms::one =
145+ // const_cast<nsStaticAtom*>(static_cast<const nsStaticAtom*>(
146+ // &detail::gGkAtoms.mAtoms[
147+ // static_cast<size_t>(detail::GkAtoms::Atoms::one)]);
148+ // nsICSSPseudoElement* nsGkAtoms::two =
149+ // const_cast<nsICSSPseudoElement*>(static_cast<const nsICSSPseudoElement*>(
150+ // &detail::gGkAtoms.mAtoms[
151+ // static_cast<size_t>(detail::GkAtoms::Atoms::two)]);
152+ // nsICSSAnonBoxPseudo* nsGkAtoms::three =
153+ // const_cast<nsICSSAnonBoxPseudo*>(static_cast<const nsICSSAnonBoxPseudo*>(
154+ // &detail::gGkAtoms.mAtoms[
155+ // static_cast<size_t>(detail::GkAtoms::Atoms::three)]);
12156
13157// Trivial subclasses of nsStaticAtom so that function signatures can require
14158// an atom from a specific atom list.
@@ -28,14 +172,24 @@ DEFINE_STATIC_ATOM_SUBCLASS(nsICSSPseudoElement)
28172namespace mozilla {
29173namespace detail {
30174
175+ // This `detail` class contains the atom strings and the atom objects.
176+ // Because they are together in a class, the mStringOffset field of the
177+ // atoms will be small and can be initialized at compile time.
178+ //
179+ // A `detail` namespace is used because the things within it aren't directly
180+ // referenced by external users of these static atoms.
31181struct GkAtoms
32182{
33- #define GK_ATOM (name_, value_, type_, atom_type_ ) NS_STATIC_ATOM_DECL_STRING(name_, value_)
183+ // The declaration of each atom's string.
184+ #define GK_ATOM (name_, value_, type_, atom_type_ ) \
185+ const char16_t name_##_string[sizeof (value_)];
34186 #include " nsGkAtomList.h"
35187 #undef GK_ATOM
36188
189+ // The enum value for each atom.
37190 enum class Atoms {
38- #define GK_ATOM (name_, value_, type_, atom_type_ ) NS_STATIC_ATOM_ENUM(name_)
191+ #define GK_ATOM (name_, value_, type_, atom_type_ ) \
192+ name_,
39193 #include " nsGkAtomList.h"
40194 #undef GK_ATOM
41195 AtomsCount
@@ -63,7 +217,12 @@ class nsGkAtoms
63217 return const_cast <nsStaticAtom*>(&sAtoms [aIndex]);
64218 }
65219
66- #define GK_ATOM (name_, value_, type_, atom_type_ ) NS_STATIC_ATOM_DECL_PTR(type_, name_)
220+ // The declaration of the pointer to each static atom.
221+ //
222+ // XXX: Eventually this should be combined with its definition and the
223+ // pointer should be made `constexpr`. See bug 1449787.
224+ #define GK_ATOM (name_, value_, type_, atom_type_ ) \
225+ static type_* name_;
67226 #include " nsGkAtomList.h"
68227 #undef GK_ATOM
69228};
0 commit comments