Bug 1449395 - Remove nsStaticAtomSetup. r=froydnj

Each nsStaticAtomSetup contains a pointer to a static atom, and also a pointer
to the canonical pointer to that static atom. Which is pretty weird! The
notable thing thing about it is that these structs are in an array, and that
gives us the only way to iterate over all static atoms in a single class, for
registration and lookups.

But thanks to various other recent changes to the implementation of static
atoms, we can now put the static atoms themselves into an array, which can be
iterated over. So this patch does that. With that done, nsStaticAtomSetup is no
longer necessary.

According to the `size` utility, on Linux64 this reduces the size of libxul.so
by the following amounts:

> text:  62008 bytes
> data:  20992 bytes
> bss:   21040 bytes
> total: 104040 bytes

- The bss reduction is one word per atom, because the canonical static atom
  pointers (e.g. nsGkAtoms::foo) have moved from .bss to .data, because they're
  now initialized at compile time instead of runtime.

- The data reduction is one word per atom, because we remove two words per atom
  for the nsStaticAtomSetup removal, but gain one word per atom from the
  previous bullet point.

- I'm not sure about the text reduction. It's three words per atom. Maybe
  because there is one less relocation per atom?

Other notable things in the patch:

- nsICSSAnonBoxPseudo and nsICSSPseudoElement now inherit from nsStaticAtom,
  not nsAtom, because that's more precise.

- Each static atoms array now has an enum associated with it, which is used in
  various ways.

- In the big comment about the macros at the top of nsStaticAtom.h, the pre-
  and post-expansion forms are now shown interleaved. The interleaving reduces
  duplication and makes the comment much easier to read and maintain. The
  comment also has an introduction that explains the constraints and goals of
  the implementation.

- The SUBCLASS macro variations are gone. There are few enough users of these
  macros now that always passing the atom type has become simpler.

MozReview-Commit-ID: 1GmfKidLjaU

--HG--
extra : rebase_source : 2352590101fc6693ba388f885ca4714a42963943
This commit is contained in:
Nicholas Nethercote 2018-03-29 11:48:18 +11:00
parent 4b941e22d0
commit 9ea93c4f7b
10 changed files with 320 additions and 264 deletions

View File

@ -21,40 +21,39 @@ extern constexpr CSSAnonBoxAtoms gCSSAnonBoxAtoms = {
NS_STATIC_ATOM_INIT_STRING(value_)
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
#define CSS_ANON_BOX(name_, value_) \
NS_STATIC_ATOM_INIT_ATOM(CSSAnonBoxAtoms, name_, value_)
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
{
#define CSS_ANON_BOX(name_, value_) \
NS_STATIC_ATOM_INIT_ATOM( \
nsICSSAnonBoxPseudo, CSSAnonBoxAtoms, name_, value_)
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
}
};
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
} // namespace detail
} // namespace mozilla
// Non-inheriting boxes must come first in nsCSSAnonBoxList.h so that
// `NonInheriting` values can index into this array and other similar arrays.
const nsStaticAtom* const nsCSSAnonBoxes::sAtoms =
mozilla::detail::gCSSAnonBoxAtoms.mAtoms;
#define CSS_ANON_BOX(name_, value_) \
NS_STATIC_ATOM_SUBCLASS_DEFN_PTR(nsICSSAnonBoxPseudo, nsCSSAnonBoxes, name_)
NS_STATIC_ATOM_DEFN_PTR( \
nsICSSAnonBoxPseudo, mozilla::detail::CSSAnonBoxAtoms, \
mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
static const nsStaticAtomSetup sCSSAnonBoxAtomSetup[] = {
// Non-inheriting boxes must come first in nsCSSAnonBoxList.h so that
// `NonInheriting` values can index into this array and other similar arrays.
#define CSS_ANON_BOX(name_, value_) \
NS_STATIC_ATOM_SUBCLASS_SETUP( \
mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
};
void nsCSSAnonBoxes::RegisterStaticAtoms()
{
NS_RegisterStaticAtoms(sCSSAnonBoxAtomSetup);
NS_RegisterStaticAtoms(sAtoms, sAtomsLen);
}
bool nsCSSAnonBoxes::IsAnonBox(nsAtom *aAtom)
{
return nsStaticAtomUtils::IsMember(aAtom, sCSSAnonBoxAtomSetup);
return nsStaticAtomUtils::IsMember(aAtom, sAtoms, sAtomsLen);
}
#ifdef MOZ_XUL
@ -71,8 +70,7 @@ nsCSSAnonBoxes::IsTreePseudoElement(nsAtom* aPseudo)
nsCSSAnonBoxes::NonInheritingTypeForPseudoTag(nsAtom* aPseudo)
{
MOZ_ASSERT(IsNonInheritingAnonBox(aPseudo));
Maybe<uint32_t> index =
nsStaticAtomUtils::Lookup(aPseudo, sCSSAnonBoxAtomSetup);
Maybe<uint32_t> index = nsStaticAtomUtils::Lookup(aPseudo, sAtoms, sAtomsLen);
MOZ_RELEASE_ASSERT(index.isSome());
return static_cast<NonInheriting>(*index);
}

View File

@ -12,9 +12,16 @@
#include "nsAtom.h"
#include "nsStaticAtom.h"
// Empty class derived from nsAtom so that function signatures can
// require an atom from this atom list.
class nsICSSAnonBoxPseudo : public nsAtom {};
// Trivial subclass of nsStaticAtom so that function signatures can require an
// atom from this atom list.
class nsICSSAnonBoxPseudo : public nsStaticAtom
{
public:
constexpr nsICSSAnonBoxPseudo(const char16_t* aStr, uint32_t aLength,
uint32_t aStringOffset)
: nsStaticAtom(aStr, aLength, aStringOffset)
{}
};
namespace mozilla {
namespace detail {
@ -25,9 +32,15 @@ struct CSSAnonBoxAtoms
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
#define CSS_ANON_BOX(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
enum class Atoms {
#define CSS_ANON_BOX(name_, value_) \
NS_STATIC_ATOM_ENUM(name_)
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
AtomsCount
};
const nsICSSAnonBoxPseudo mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
};
extern const CSSAnonBoxAtoms gCSSAnonBoxAtoms;
@ -50,10 +63,16 @@ public:
aPseudo == firstLetterContinuation;
}
#define CSS_ANON_BOX(name_, value_) \
NS_STATIC_ATOM_SUBCLASS_DECL_PTR(nsICSSAnonBoxPseudo, name_)
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
private:
static const nsStaticAtom* const sAtoms;
static constexpr size_t sAtomsLen =
mozilla::ArrayLength(mozilla::detail::gCSSAnonBoxAtoms.mAtoms);
public:
#define CSS_ANON_BOX(name_, value_) \
NS_STATIC_ATOM_DECL_PTR(nsICSSAnonBoxPseudo, name_)
#include "nsCSSAnonBoxList.h"
#undef CSS_ANON_BOX
typedef uint8_t NonInheritingBase;
enum class NonInheriting : NonInheritingBase {

View File

@ -24,35 +24,30 @@ extern constexpr CSSPseudoElementAtoms gCSSPseudoElementAtoms = {
NS_STATIC_ATOM_INIT_STRING(value_)
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
NS_STATIC_ATOM_INIT_ATOM(CSSPseudoElementAtoms, name_, value_)
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
{
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
NS_STATIC_ATOM_INIT_ATOM( \
nsICSSPseudoElement, CSSPseudoElementAtoms, name_, value_)
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
}
};
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
} // namespace detail
} // namespace mozilla
const nsStaticAtom* const nsCSSPseudoElements::sAtoms =
mozilla::detail::gCSSPseudoElementAtoms.mAtoms;
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
NS_STATIC_ATOM_SUBCLASS_DEFN_PTR( \
nsICSSPseudoElement, nsCSSPseudoElements, name_)
NS_STATIC_ATOM_DEFN_PTR( \
nsICSSPseudoElement, mozilla::detail::CSSPseudoElementAtoms, \
mozilla::detail::gCSSPseudoElementAtoms, nsCSSPseudoElements, name_);
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
// Array of nsStaticAtomSetup for each of the pseudo-elements.
static const nsStaticAtomSetup sCSSPseudoElementAtomSetup[] = {
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
NS_STATIC_ATOM_SUBCLASS_SETUP( \
detail::gCSSPseudoElementAtoms, nsCSSPseudoElements, name_)
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
};
// Flags data for each of the pseudo-elements, which must be separate
// from the previous array since there's no place for it in
// nsStaticAtomSetup.
// Flags data for each of the pseudo-elements.
/* static */ const uint32_t
nsCSSPseudoElements::kPseudoElementFlags[] = {
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
@ -63,12 +58,12 @@ nsCSSPseudoElements::kPseudoElementFlags[] = {
void nsCSSPseudoElements::RegisterStaticAtoms()
{
NS_RegisterStaticAtoms(sCSSPseudoElementAtomSetup);
NS_RegisterStaticAtoms(sAtoms, sAtomsLen);
}
bool nsCSSPseudoElements::IsPseudoElement(nsAtom *aAtom)
{
return nsStaticAtomUtils::IsMember(aAtom, sCSSPseudoElementAtomSetup);
return nsStaticAtomUtils::IsMember(aAtom, sAtoms, sAtomsLen);
}
/* static */ bool
@ -94,8 +89,7 @@ nsCSSPseudoElements::IsCSS2PseudoElement(nsAtom *aAtom)
/* static */ CSSPseudoElementType
nsCSSPseudoElements::GetPseudoType(nsAtom *aAtom, EnabledState aEnabledState)
{
Maybe<uint32_t> index =
nsStaticAtomUtils::Lookup(aAtom, sCSSPseudoElementAtomSetup);
Maybe<uint32_t> index = nsStaticAtomUtils::Lookup(aAtom, sAtoms, sAtomsLen);
if (index.isSome()) {
auto type = static_cast<Type>(*index);
// ::moz-placeholder is an alias for ::placeholder
@ -125,9 +119,9 @@ nsCSSPseudoElements::GetPseudoType(nsAtom *aAtom, EnabledState aEnabledState)
/* static */ nsAtom*
nsCSSPseudoElements::GetPseudoAtom(Type aType)
{
NS_ASSERTION(aType < Type::Count, "Unexpected type");
return *sCSSPseudoElementAtomSetup[
static_cast<CSSPseudoElementTypeBase>(aType)].mAtomp;
MOZ_ASSERT(aType < Type::Count, "Unexpected type");
return const_cast<nsStaticAtom*>(
&sAtoms[static_cast<CSSPseudoElementTypeBase>(aType)]);
}
/* static */ already_AddRefed<nsAtom>

View File

@ -56,6 +56,17 @@
// grid containers) and thus needs parent display-based style fixup?
#define CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM (1<<7)
// Trivial subclass of nsStaticAtom so that function signatures can require an
// atom from this atom list.
class nsICSSPseudoElement : public nsStaticAtom
{
public:
constexpr nsICSSPseudoElement(const char16_t* aStr, uint32_t aLength,
uint32_t aStringOffset)
: nsStaticAtom(aStr, aLength, aStringOffset)
{}
};
namespace mozilla {
// The total count of CSSPseudoElement is less than 256,
@ -88,10 +99,15 @@ struct CSSPseudoElementAtoms
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
NS_STATIC_ATOM_DECL_ATOM(name_)
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
enum class Atoms {
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
NS_STATIC_ATOM_ENUM(name_)
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
AtomsCount
};
const nsICSSPseudoElement mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
};
extern const CSSPseudoElementAtoms gCSSPseudoElementAtoms;
@ -100,10 +116,6 @@ extern const CSSPseudoElementAtoms gCSSPseudoElementAtoms;
} // namespace mozilla
// Empty class derived from nsAtom so that function signatures can
// require an atom from this atom list.
class nsICSSPseudoElement : public nsAtom {};
class nsCSSPseudoElements
{
typedef mozilla::CSSPseudoElementType Type;
@ -124,10 +136,16 @@ public:
return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_IS_CSS2);
}
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
NS_STATIC_ATOM_SUBCLASS_DECL_PTR(nsICSSPseudoElement, name_)
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
private:
static const nsStaticAtom* const sAtoms;
static constexpr size_t sAtomsLen =
mozilla::ArrayLength(mozilla::detail::gCSSPseudoElementAtoms.mAtoms);
public:
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
NS_STATIC_ATOM_DECL_PTR(nsICSSPseudoElement, name_);
#include "nsCSSPseudoElementList.h"
#undef CSS_PSEUDO_ELEMENT
static Type GetPseudoType(nsAtom* aAtom, EnabledState aEnabledState);

View File

@ -279,7 +279,7 @@ public:
already_AddRefed<nsAtom> Atomize(const nsACString& aUTF8String);
already_AddRefed<nsAtom> AtomizeMainThread(const nsAString& aUTF16String);
nsStaticAtom* GetStaticAtom(const nsAString& aUTF16String);
void RegisterStaticAtoms(const nsStaticAtomSetup* aSetup, uint32_t aCount);
void RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen);
// The result of this function may be imprecise if other threads are operating
// on atoms concurrently. It's also slow, since it triggers a GC before
@ -647,16 +647,13 @@ nsAtomSubTable::AddSizeOfExcludingThisLocked(MallocSizeOf aMallocSizeOf,
}
void
nsAtomTable::RegisterStaticAtoms(const nsStaticAtomSetup* aSetup,
uint32_t aCount)
nsAtomTable::RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!gStaticAtomsDone, "Static atom insertion is finished!");
for (uint32_t i = 0; i < aCount; ++i) {
const nsStaticAtom* atom = aSetup[i].mAtom;
nsStaticAtom** atomp = aSetup[i].mAtomp;
for (uint32_t i = 0; i < aAtomsLen; ++i) {
const nsStaticAtom* atom = &aAtoms[i];
MOZ_ASSERT(nsCRT::IsAscii(atom->String()));
MOZ_ASSERT(NS_strlen(atom->String()) == atom->GetLength());
@ -676,15 +673,15 @@ nsAtomTable::RegisterStaticAtoms(const nsStaticAtomSetup* aSetup,
he->mAtom->ToUTF8String(name);
MOZ_CRASH_UNSAFE_PRINTF("Atom for '%s' already exists", name.get());
}
he->mAtom = *atomp = const_cast<nsStaticAtom*>(atom);
he->mAtom = const_cast<nsStaticAtom*>(atom);
}
}
void
RegisterStaticAtoms(const nsStaticAtomSetup* aSetup, uint32_t aCount)
NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen)
{
MOZ_ASSERT(gAtomTable);
gAtomTable->RegisterStaticAtoms(aSetup, aCount);
gAtomTable->RegisterStaticAtoms(aAtoms, aAtomsLen);
}
already_AddRefed<nsAtom>

View File

@ -14,30 +14,29 @@ extern constexpr GkAtoms gGkAtoms = {
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_INIT_STRING(value_)
#include "nsGkAtomList.h"
#undef GK_ATOM
#define GK_ATOM(name_, value_) \
NS_STATIC_ATOM_INIT_ATOM(GkAtoms, name_, value_)
#include "nsGkAtomList.h"
#undef GK_ATOM
{
#define GK_ATOM(name_, value_) \
NS_STATIC_ATOM_INIT_ATOM(nsStaticAtom, GkAtoms, name_, value_)
#include "nsGkAtomList.h"
#undef GK_ATOM
}
};
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
} // namespace detail
} // namespace mozilla
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DEFN_PTR(nsGkAtoms, name_)
const nsStaticAtom* const nsGkAtoms::sAtoms = mozilla::detail::gGkAtoms.mAtoms;
#define GK_ATOM(name_, value_) \
NS_STATIC_ATOM_DEFN_PTR( \
nsStaticAtom, mozilla::detail::GkAtoms, mozilla::detail::gGkAtoms, \
nsGkAtoms, name_)
#include "nsGkAtomList.h"
#undef GK_ATOM
static const nsStaticAtomSetup sGkAtomSetup[] = {
#define GK_ATOM(name_, value_) \
NS_STATIC_ATOM_SETUP(mozilla::detail::gGkAtoms, nsGkAtoms, name_)
#include "nsGkAtomList.h"
#undef GK_ATOM
};
void nsGkAtoms::RegisterStaticAtoms()
{
NS_RegisterStaticAtoms(sGkAtomSetup);
NS_RegisterStaticAtoms(sAtoms, sAtomsLen);
}

View File

@ -19,9 +19,14 @@ struct GkAtoms
#include "nsGkAtomList.h"
#undef GK_ATOM
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
#include "nsGkAtomList.h"
#undef GK_ATOM
enum class Atoms {
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_ENUM(name_)
#include "nsGkAtomList.h"
#undef GK_ATOM
AtomsCount
};
const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
};
extern const GkAtoms gGkAtoms;
@ -31,10 +36,15 @@ extern const GkAtoms gGkAtoms;
class nsGkAtoms
{
private:
static const nsStaticAtom* const sAtoms;
static constexpr size_t sAtomsLen =
mozilla::ArrayLength(mozilla::detail::gGkAtoms.mAtoms);
public:
static void RegisterStaticAtoms();
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(name_)
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(nsStaticAtom, name_)
#include "nsGkAtomList.h"
#undef GK_ATOM
};

View File

@ -9,10 +9,45 @@
#include <stdint.h>
#include "nsAtom.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Maybe.h"
// The following macros are used to define static atoms, typically in
// conjunction with a .h file that defines the names and values of the atoms.
// Static atoms are structured carefully to satisfy a lot of constraints.
//
// - We have ~2700 static atoms. They are divided across ~4 classes, with the
// majority in nsGkAtoms.
//
// - 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 computed 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. Ideally this would be constexpr
// so it doesn't take up any space in memory. Unfortunately MSVC's constexpr
// support is buggy and so this isn't possible yet. See bug 1449787.
//
// - 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.
//
// The macros below are used to define static atoms in a way that satisfies
// these constraints. They are used in conjunction with a .h file that defines
// the names and values of the atoms.
//
// For example, the .h file might be called MyAtomList.h and look like this:
//
@ -20,60 +55,9 @@
// MY_ATOM(two, "two")
// MY_ATOM(three, "three")
//
// The code defining the static atoms should look something like this:
//
// ====> MyAtoms.h <====
//
// namespace detail {
//
// struct MyAtoms
// {
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
// #include "MyAtomList.h"
// #undef MY_ATOM
//
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// };
//
// extern const MyAtoms gMyAtoms;
//
// } // namespace detail
//
// class nsMyAtoms
// {
// public:
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// };
//
// ====> MyAtoms.cpp <====
//
// MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
// static constexpr MyAtoms gMyAtoms = {
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_STRING(value_)
// #include "MyAtomList.h"
// #undef MY_ATOM
//
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_ATOM(MyAtoms, name_, value_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// };
// MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
//
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DEFN_PTR(nsMyAtoms, name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
//
// static const nsStaticAtomSetup sMyAtomSetup[] = {
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_SETUP(mozilla::detail::gMyAtoms, nsMyAtoms, name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// };
//
// The macros expand to the following:
// The code defining the static atoms should look something like the following.
// ("<<<"/"---"/">>>" markers are used below to indicate what the macros look
// like before and after expansion.)
//
// ====> MyAtoms.h <====
//
@ -86,15 +70,34 @@
// // atoms will be small and can be initialized at compile time.
// struct MyAtoms
// {
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// const char16_t one_string[4];
// const char16_t two_string[4];
// const char16_t three_string[6];
// >>>
//
// const nsStaticAtom one_atom;
// const nsStaticAtom two_atom;
// const nsStaticAtom three_atom;
// enum class Atoms {
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_ENUM(name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// one,
// two,
// three,
// >>>
// AtomsCount
// };
//
// const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
// };
//
// // The MyAtoms instance is `extern const` so it can be defined in a .cpp
// // file.
// extern const MyAtoms gMyAtoms;
//
// } // namespace detail
@ -102,147 +105,158 @@
// // This class holds the pointers to the individual atoms.
// class nsMyAtoms
// {
// private:
// // 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 =
// mozilla::ArrayLength(detail::gMyAtoms.mAtoms);
//
// public:
// // The type is not `nsStaticAtom* const` -- even though these atoms are
// // immutable -- because they are often passed to functions with
// // `nsAtom*` parameters, i.e. that can be passed both dynamic and
// // static.
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(nsStaticAtom, name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// static nsStaticAtom* one;
// static nsStaticAtom* two;
// static nsStaticAtom* three;
// >>>
// };
//
// ====> MyAtoms.cpp <====
//
// namespace detail {
//
// // Need to suppress some MSVC warning weirdness with WrappingMultiply().
// MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
// // Because this is `constexpr` it ends up in read-only memory where it can
// // be shared between processes.
// extern constexpr MyAtoms gMyAtoms = {
// static constexpr MyAtoms gMyAtoms = {
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_STRING(value_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// u"one",
// u"two",
// u"three",
//
// nsStaticAtom(u"one", 3, offsetof(MyAtoms, one_atom) -
// offsetof(MyAtoms, one_string)),
// nsStaticAtom(u"two", 3, offsetof(MyAtoms, two_atom) -
// offsetof(MyAtoms, two_string)),
// nsStaticAtom(u"three", 3, offsetof(MyAtoms, three_atom) -
// offsetof(MyAtoms, three_string)),
// >>>
// {
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_ATOM(nsStaticAtom, MyAtoms, name_, value_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// nsStaticAtom(
// u"one", 3,
// offsetof(MyAtoms, mAtoms[static_cast<size_t>(MyAtoms::Atoms::one)]) -
// offsetof(MyAtoms, one_string)),
// nsStaticAtom(
// u"two", 3,
// offsetof(MyAtoms, mAtoms[static_cast<size_t>(MyAtoms::Atoms::two)]) -
// offsetof(MyAtoms, two_string)),
// nsStaticAtom(
// u"three", 3,
// offsetof(MyAtoms, mAtoms[static_cast<size_t>(MyAtoms::Atoms::three)]) -
// offsetof(MyAtoms, three_string)),
// >>>
// }
// };
// MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
//
// nsStaticAtom* MyAtoms::one;
// nsStaticAtom* MyAtoms::two;
// nsStaticAtom* MyAtoms::three;
// } // namespace detail
//
// static const nsStaticAtomSetup sMyAtomSetup[] = {
// { &detail::gMyAtoms.one_atom, &nsMyAtoms::one },
// { &detail::gMyAtoms.two_atom, &nsMyAtoms::two },
// { &detail::gMyAtoms.three_atom, &nsMyAtoms::three },
// };
// const nsStaticAtom* const nsMyAtoms::sAtoms =
// mozilla::detail::gMyAtoms.mAtoms;
//
// When RegisterStaticAtoms(sMyAtomSetup) is called it iterates over
// sMyAtomSetup[]. E.g. for the first atom it does roughly the following:
// - MyAtoms::one = one_atom
// - inserts one_atom into the atom table
// <<<
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DEFN_PTR(nsStaticAtom, detail::MyAtoms, detail::gMyAtoms, nsMyAtoms, name_)
// #include "MyAtomList.h"
// #undef MY_ATOM
// ---
// nsStaticAtom* nsMyAtoms::one =
// const_cast<nsStaticAtom*>(&detail::gMyAtoms.mAtoms[
// static_cast<size_t>(detail::MyAtoms::Atoms::one)]);
// nsStaticAtom* nsMyAtoms::two =
// const_cast<nsStaticAtom*>(&detail::gMyAtoms.mAtoms[
// static_cast<size_t>(detail::MyAtoms::Atoms::two)]);
// nsStaticAtom* nsMyAtoms::three =
// const_cast<nsStaticAtom*>(&detail::gMyAtoms.mAtoms[
// static_cast<size_t>(detail::MyAtoms::Atoms::three)]);
// >>>
//
// When NS_RegisterStaticAtoms(sAtoms, sAtomsLen) is called it iterates
// over the atoms, inserting them into the atom table.
// The declaration of the atom's string, which must be within the same `detail`
// class as NS_STATIC_ATOM_DECL_ATOM.
// The declaration of the atom's string.
#define NS_STATIC_ATOM_DECL_STRING(name_, value_) \
const char16_t name_##_string[sizeof(value_)];
// The declaration of the static atom itself, which must be within the same
// `detail` class as NS_STATIC_ATOM_DECL_STRING.
#define NS_STATIC_ATOM_DECL_ATOM(name_) \
const nsStaticAtom name_##_atom;
// The enum value for the atom.
#define NS_STATIC_ATOM_ENUM(name_) \
name_,
// The declaration of the pointer to the static atom, which must be within
// a class.
#define NS_STATIC_ATOM_DECL_PTR(name_) \
static nsStaticAtom* name_;
// Like NS_STATIC_ATOM_DECL, but for sub-classes of nsStaticAtom.
#define NS_STATIC_ATOM_SUBCLASS_DECL_PTR(type_, name_) \
// The declaration of the pointer to the static atom. `type_` must be
// `nsStaticAtom` or a subclass thereof.
// XXX: Eventually this should be combined with NS_STATIC_ATOM_DEFN_PTR and the
// pointer should be made `constexpr`. See bug 1449787.
#define NS_STATIC_ATOM_DECL_PTR(type_, name_) \
static type_* name_;
// The initialization of the atom's string, which must be within a `constexpr`
// instance of the `detail` class.
// The initialization of the atom's string.
#define NS_STATIC_ATOM_INIT_STRING(value_) \
u"" value_,
// The initialization of the static atom itself, which must be within a
// `constexpr` instance of the `detail` class.
// The initialization of the atom itself. `type_` must be `nsStaticAtom` or a
// subclass thereof.
//
// Note that |value_| is an 8-bit string, and so |sizeof(value_)| is equal
// to the number of chars (including the terminating '\0'). The |u""| prefix
// converts |value_| to a 16-bit string.
#define NS_STATIC_ATOM_INIT_ATOM(class_, name_, value_) \
nsStaticAtom(u"" value_, \
sizeof(value_) - 1, \
offsetof(class_, name_##_atom) - \
offsetof(class_, name_##_string)),
#define NS_STATIC_ATOM_INIT_ATOM(type_, detailClass_, name_, value_) \
type_(u"" value_, \
sizeof(value_) - 1, \
offsetof(detailClass_, \
mAtoms[static_cast<size_t>(detailClass_::Atoms::name_)]) - \
offsetof(detailClass_, name_##_string)),
// The definition of the pointer to the static atom. Initially null, it is
// set by RegisterStaticAtoms() to point to a heap-allocated nsStaticAtom.
#define NS_STATIC_ATOM_DEFN_PTR(class_, name_) \
nsStaticAtom* class_::name_;
// Like NS_STATIC_ATOM_DEFN, but for sub-classes of nsStaticAtom.
#define NS_STATIC_ATOM_SUBCLASS_DEFN_PTR(type_, class_, name_) \
type_* class_::name_;
// The StaticAtomSetup. Used during start-up, and in some cases afterwards.
#define NS_STATIC_ATOM_SETUP(detailObj_, class_, name_) \
{ &detailObj_.name_##_atom, &class_::name_ },
// Like NS_STATIC_ATOM_SUBCLASS, but for sub-classes of nsStaticAtom.
#define NS_STATIC_ATOM_SUBCLASS_SETUP(detailObj_, class_, name_) \
{ &detailObj_.name_##_atom, \
reinterpret_cast<nsStaticAtom**>(&class_::name_) },
// Holds data used to initialize large number of atoms during startup. Use
// NS_STATIC_ATOM_SETUP to initialize these structs.
struct nsStaticAtomSetup
{
const nsStaticAtom* const mAtom;
nsStaticAtom** const mAtomp;
};
// Definition of the pointer to the static atom. `type_` must be `nsStaticAtom`
// or a subclass thereof.
#define NS_STATIC_ATOM_DEFN_PTR(type_, detailClass_, detailObj_, class_, name_) \
type_* class_::name_ = const_cast<type_*>( \
&detailObj_.mAtoms[static_cast<size_t>(detailClass_::Atoms::name_)]);
// Register an array of static atoms with the atom table.
template<uint32_t N>
void
NS_RegisterStaticAtoms(const nsStaticAtomSetup (&aSetup)[N])
{
extern void RegisterStaticAtoms(const nsStaticAtomSetup* aSetup,
uint32_t aCount);
RegisterStaticAtoms(aSetup, N);
}
NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen);
// This class holds basic operations on arrays of static atoms.
class nsStaticAtomUtils {
public:
template<uint32_t N>
static mozilla::Maybe<uint32_t> Lookup(nsAtom *aAtom,
const nsStaticAtomSetup (&aSetup)[N])
{
return Lookup(aAtom, aSetup, N);
}
template<uint32_t N>
static bool IsMember(nsAtom *aAtom, const nsStaticAtomSetup (&aSetup)[N])
{
return Lookup(aAtom, aSetup, N).isSome();
}
private:
static mozilla::Maybe<uint32_t> Lookup(nsAtom* aAtom,
const nsStaticAtomSetup* aSetup,
const nsStaticAtom* aAtoms,
uint32_t aCount)
{
for (uint32_t i = 0; i < aCount; i++) {
if (aAtom == *(aSetup[i].mAtomp)) {
if (aAtom == &aAtoms[i]) {
return mozilla::Some(i);
}
}
return mozilla::Nothing();
}
static bool IsMember(nsAtom* aAtom, const nsStaticAtom* aAtoms,
uint32_t aCount)
{
return Lookup(aAtom, aAtoms, aCount).isSome();
}
};
#endif

View File

@ -102,30 +102,28 @@ extern constexpr DirectoryAtoms gDirectoryAtoms = {
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_INIT_STRING(value_)
#include "nsDirectoryServiceAtomList.h"
#undef DIR_ATOM
#define DIR_ATOM(name_, value_) \
NS_STATIC_ATOM_INIT_ATOM(DirectoryAtoms, name_, value_)
#include "nsDirectoryServiceAtomList.h"
#undef DIR_ATOM
{
#define DIR_ATOM(name_, value_) \
NS_STATIC_ATOM_INIT_ATOM(nsStaticAtom, DirectoryAtoms, name_, value_)
#include "nsDirectoryServiceAtomList.h"
#undef DIR_ATOM
}
};
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
} // namespace detail
} // namespace mozilla
const nsStaticAtom* const nsDirectoryService::sAtoms =
mozilla::detail::gDirectoryAtoms.mAtoms;
#define DIR_ATOM(name_, value_) \
NS_STATIC_ATOM_DEFN_PTR(nsDirectoryService, name_)
NS_STATIC_ATOM_DEFN_PTR( \
nsStaticAtom, mozilla::detail::DirectoryAtoms, \
mozilla::detail::gDirectoryAtoms, nsDirectoryService, name_)
#include "nsDirectoryServiceAtomList.h"
#undef DIR_ATOM
static const nsStaticAtomSetup sDirectoryServiceAtomSetup[] = {
#define DIR_ATOM(name_, value_) \
NS_STATIC_ATOM_SETUP( \
mozilla::detail::gDirectoryAtoms, nsDirectoryService, name_)
#include "nsDirectoryServiceAtomList.h"
#undef DIR_ATOM
};
NS_IMETHODIMP
nsDirectoryService::Init()
{
@ -141,7 +139,7 @@ nsDirectoryService::RealInit()
gService = new nsDirectoryService();
NS_RegisterStaticAtoms(sDirectoryServiceAtomSetup);
NS_RegisterStaticAtoms(sAtoms, sAtomsLen);
// Let the list hold the only reference to the provider.
nsAppFileLocationProvider* defaultProvider = new nsAppFileLocationProvider;

View File

@ -30,9 +30,14 @@ struct DirectoryAtoms
#include "nsDirectoryServiceAtomList.h"
#undef DIR_ATOM
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
#include "nsDirectoryServiceAtomList.h"
#undef DIR_ATOM
enum class Atoms {
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_ENUM(name_)
#include "nsDirectoryServiceAtomList.h"
#undef DIR_ATOM
AtomsCount
};
const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
};
extern const DirectoryAtoms gDirectoryAtoms;
@ -74,8 +79,12 @@ private:
nsInterfaceHashtable<nsCStringHashKey, nsIFile> mHashtable;
nsTArray<nsCOMPtr<nsIDirectoryServiceProvider>> mProviders;
static const nsStaticAtom* const sAtoms;
static constexpr size_t sAtomsLen =
mozilla::ArrayLength(mozilla::detail::gDirectoryAtoms.mAtoms);
public:
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(name_)
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(nsStaticAtom, name_)
#include "nsDirectoryServiceAtomList.h"
#undef DIR_ATOM
};