diff options
Diffstat (limited to '')
-rw-r--r-- | xpcom/ds/nsGkAtoms.h | 192 |
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___ */ |