summaryrefslogtreecommitdiffstats
path: root/xpcom/ds/nsGkAtoms.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--xpcom/ds/nsGkAtoms.h192
1 files changed, 192 insertions, 0 deletions
diff --git a/xpcom/ds/nsGkAtoms.h b/xpcom/ds/nsGkAtoms.h
new file mode 100644
index 0000000000..eba33bf95c
--- /dev/null
+++ b/xpcom/ds/nsGkAtoms.h
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsGkAtoms_h___
+#define nsGkAtoms_h___
+
+#include "nsAtom.h"
+
+// Static atoms are structured carefully to satisfy a lot of constraints.
+//
+// - We have ~2300 static atoms.
+//
+// - We want them to be constexpr so they end up in .rodata, and thus shared
+// between processes, minimizing memory usage.
+//
+// - We need them to be in an array, so we can iterate over them (for
+// registration and lookups).
+//
+// - Each static atom has a string literal associated with it. We can't use a
+// pointer to the string literal because then the atoms won't end up in
+// .rodata. Therefore the string literals and the atoms must be arranged in a
+// way such that a numeric index can be used instead. This numeric index
+// (nsStaticAtom::mStringOffset) must be computable at compile-time to keep
+// the static atom constexpr. It should also not be too large (a uint32_t is
+// reasonable).
+//
+// - Each static atom stores the hash value of its associated string literal;
+// it's used in various ways. The hash value must be specified at
+// compile-time, to keep the static atom constexpr.
+//
+// - As well as accessing each static atom via array indexing, we need an
+// individual pointer, e.g. nsGkAtoms::foo. We want this to be constexpr so
+// it doesn't take up any space in memory.
+//
+// - The array of static atoms can't be in a .h file, because it's a huge
+// constexpr expression, which would blow out compile times. But the
+// individual pointers for the static atoms must be in a .h file so they are
+// public.
+//
+// nsGkAtoms below defines static atoms in a way that satisfies these
+// constraints. It uses nsGkAtomList.h, which defines the names and values of
+// the atoms. nsGkAtomList.h is generated by StaticAtoms.py and has entries
+// that look like this:
+//
+// GK_ATOM(a, "a", 0x01234567, nsStaticAtom, Atom)
+// GK_ATOM(bb, "bb", 0x12345678, nsCSSPseudoElementStaticAtom,
+// PseudoElementAtom)
+// GK_ATOM(Ccc, "Ccc", 0x23456789, nsCSSAnonBoxPseudoStaticAtom,
+// InheritingAnonBoxAtom)
+//
+// Comments throughout this file and nsGkAtoms.cpp show how these entries get
+// expanded by macros.
+
+// Trivial subclasses of nsStaticAtom so that function signatures can require
+// an atom from a specific atom list.
+#define DEFINE_STATIC_ATOM_SUBCLASS(name_) \
+ class name_ : public nsStaticAtom { \
+ public: \
+ constexpr name_(uint32_t aLength, uint32_t aHash, uint32_t aOffset, \
+ bool aIsAsciiLowercase) \
+ : nsStaticAtom(aLength, aHash, aOffset, aIsAsciiLowercase) {} \
+ };
+
+DEFINE_STATIC_ATOM_SUBCLASS(nsCSSAnonBoxPseudoStaticAtom)
+DEFINE_STATIC_ATOM_SUBCLASS(nsCSSPseudoElementStaticAtom)
+
+#undef DEFINE_STATIC_ATOM_SUBCLASS
+
+namespace mozilla {
+namespace detail {
+
+// This `detail` class contains the atom strings and the atom objects. Because
+// they are together in a class, the `mStringOffset` field of the atoms will be
+// small and can be initialized at compile time.
+//
+// A `detail` namespace is used because the things within it aren't directly
+// referenced by external users of these static atoms.
+struct GkAtoms {
+// The declaration of each atom's string.
+//
+// Expansion of the example GK_ATOM entries from above:
+//
+// const char16_t a_string[sizeof("a")];
+// const char16_t bb_string[sizeof("bb")];
+// const char16_t Ccc_string[sizeof("Ccc")];
+//
+#define GK_ATOM(name_, value_, hash_, is_ascii_lower_, type_, atom_type_) \
+ const char16_t name_##_string[sizeof(value_)];
+#include "nsGkAtomList.h"
+#undef GK_ATOM
+
+ // The enum value for each atom.
+ enum class Atoms {
+// Expansion of the example GK_ATOM entries above:
+//
+// a,
+// bb,
+// Ccc,
+//
+#define GK_ATOM(name_, value_, hash_, is_ascii_lower_, type_, atom_type_) name_,
+#include "nsGkAtomList.h"
+#undef GK_ATOM
+ AtomsCount
+ };
+
+ const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
+};
+
+// The offset from the start of the GkAtoms object to the start of the
+// nsStaticAtom array inside it. This is used in Rust to avoid problems
+// with lld-link.exe on Windows when rust-bindgen generates a non-opaque
+// version of GkAtoms.
+//
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1517685
+const ptrdiff_t kGkAtomsArrayOffset = offsetof(GkAtoms, mAtoms);
+
+// The GkAtoms instance is `extern const` so it can be defined in a .cpp file.
+//
+// XXX: The NS_EXTERNAL_VIS is necessary to work around an apparent GCC bug:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87494
+#if defined(__GNUC__) && !defined(__clang__)
+extern NS_EXTERNAL_VIS const GkAtoms gGkAtoms;
+#else
+extern const GkAtoms gGkAtoms;
+#endif
+
+} // namespace detail
+} // namespace mozilla
+
+// This class holds the pointers to the individual atoms.
+class nsGkAtoms {
+ private:
+ friend void NS_InitAtomTable();
+
+ // This is a useful handle to the array of atoms, used below and also
+ // possibly by Rust code.
+ static const nsStaticAtom* const sAtoms;
+
+ // The number of atoms, used below.
+ static constexpr size_t sAtomsLen =
+ static_cast<size_t>(mozilla::detail::GkAtoms::Atoms::AtomsCount);
+
+ public:
+ static nsStaticAtom* GetAtomByIndex(size_t aIndex) {
+ MOZ_ASSERT(aIndex < sAtomsLen);
+ return const_cast<nsStaticAtom*>(&sAtoms[aIndex]);
+ }
+
+ static size_t IndexOf(const nsStaticAtom* atom) {
+ nsStaticAtom* firstAtom = GetAtomByIndex(0);
+ size_t ret = atom - firstAtom;
+ MOZ_ASSERT(ret < sAtomsLen);
+ return ret;
+ }
+
+// The definition of the pointer to each static atom.
+//
+// These types are not `static constexpr <type>* const` -- even though these
+// atoms are immutable -- because they are often passed to functions with
+// `nsAtom*` parameters that can be passed both dynamic and static atoms.
+//
+// Expansion of the example GK_ATOM entries above:
+//
+// static constexpr nsStaticAtom* a =
+// const_cast<nsStaticAtom*>(
+// &mozilla::detail::gGkAtoms.mAtoms[
+// static_cast<size_t>(mozilla::detail::GkAtoms::Atoms::a)]);
+//
+// static constexpr nsStaticAtom* bb =
+// const_cast<nsStaticAtom*>(
+// &mozilla::detail::gGkAtoms.mAtoms[
+// static_cast<size_t>(mozilla::detail::GkAtoms::Atoms::bb)]);
+//
+// static constexpr nsStaticAtom* Ccc =
+// const_cast<nsStaticAtom*>(
+// &mozilla::detail::gGkAtoms.mAtoms[
+// static_cast<size_t>(mozilla::detail::GkAtoms::Atoms::Ccc)]);
+//
+#define GK_ATOM(name_, value_, hash_, is_ascii_lower_, type_, atom_type_) \
+ static constexpr nsStaticAtom* name_ = const_cast<nsStaticAtom*>( \
+ &mozilla::detail::gGkAtoms.mAtoms[static_cast<size_t>( \
+ mozilla::detail::GkAtoms::Atoms::name_)]);
+#include "nsGkAtomList.h"
+#undef GK_ATOM
+};
+
+inline bool nsAtom::IsEmpty() const { return this == nsGkAtoms::_empty; }
+
+#endif /* nsGkAtoms_h___ */