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/. */
12 // Static atoms are structured carefully to satisfy a lot of constraints.
14 // - We have ~2300 static atoms.
16 // - We want them to be constexpr so they end up in .rodata, and thus shared
17 // between processes, minimizing memory usage.
19 // - We need them to be in an array, so we can iterate over them (for
20 // registration and lookups).
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
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.
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.
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
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
48 // nsGkAtomList.h is generated by StaticAtoms.py and has entries that look
51 // GK_ATOM(one, "one", 0x01234567, nsStaticAtom, Atom)
52 // GK_ATOM(two, "two", 0x12345678, nsICSSPseudoElement, PseudoElementAtom)
53 // GK_ATOM(three, "three", 0x23456789, nsICSSAnonBoxPseudo, InheritingAnonBoxAtom)
55 // After macro expansion, the atom definitions look like the following:
57 // ====> nsGkAtoms.h <====
59 // namespace mozilla {
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")];
69 // // The enum value for each atom.
77 // const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
80 // } // namespace detail
81 // } // namespace mozilla
83 // // This class holds the pointers to the individual atoms.
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;
91 // // The number of atoms, used below.
92 // static constexpr size_t sAtomsLen =
93 // static_cast<size_t>(detail::MyAtoms::Atoms::AtomsCount);
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
100 // static nsStaticAtom* one;
101 // static nsICSSPseudoElement* two;
102 // static nsICSSAnonBoxPseudo* three;
105 // ====> nsGkAtoms.cpp <====
107 // namespace mozilla {
108 // namespace detail {
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.
120 // // The initialization of the atoms themselves.
124 // offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::one)]) -
125 // offsetof(GkAtoms, one_string)),
129 // offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::two)]) -
130 // offsetof(GkAtoms, two_string)),
134 // offsetof(GkAtoms, mAtoms[static_cast<size_t>(GkAtoms::Atoms::three)]) -
135 // offsetof(GkAtoms, three_string)),
138 // MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
140 // } // namespace detail
141 // } // namespace mozilla
143 // const nsStaticAtom* const nsGkAtoms::sAtoms =
144 // mozilla::detail::gGkAtoms.mAtoms;
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)]);
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 \
166 constexpr name_(const char16_t* aStr, uint32_t aLength, \
167 uint32_t aHash, uint32_t aOffset) \
168 : nsStaticAtom(aStr, aLength, aHash, aOffset) {} \
171 DEFINE_STATIC_ATOM_SUBCLASS(nsICSSAnonBoxPseudo
)
172 DEFINE_STATIC_ATOM_SUBCLASS(nsICSSPseudoElement
)
174 #undef DEFINE_STATIC_ATOM_SUBCLASS
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.
183 // A `detail` namespace is used because the things within it aren't directly
184 // referenced by external users of these static atoms.
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"
193 // The enum value for each atom.
195 #define GK_ATOM(name_, value_, hash_, type_, atom_type_) \
197 #include "nsGkAtomList.h"
202 const nsStaticAtom mAtoms
[static_cast<size_t>(Atoms::AtomsCount
)];
205 } // namespace detail
206 } // namespace mozilla
211 static const nsStaticAtom
* const sAtoms
;
212 static constexpr size_t sAtomsLen
=
213 static_cast<size_t>(mozilla::detail::GkAtoms::Atoms::AtomsCount
);
216 static void RegisterStaticAtoms();
218 static nsStaticAtom
* GetAtomByIndex(size_t aIndex
)
220 MOZ_ASSERT(aIndex
< sAtomsLen
);
221 return const_cast<nsStaticAtom
*>(&sAtoms
[aIndex
]);
224 // The declaration of the pointer to each static atom.
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_) \
230 #include "nsGkAtomList.h"
234 #endif /* nsGkAtoms_h___ */