mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1411469 - Statically allocate static atoms. r=froydnj
Currently static atoms are stored on the heap, but their char buffers are stored in read-only static memory. This patch changes the representation of nsStaticAtom (thus making it a non-trivial subclass of nsAtom). Instead of a pointer to the string, it now has an mStringOffset field which is a 32-bit offset to the string. (This requires placement of the string and the atom within the same object so that the offset is known to be small. The docs and macros in nsStaticAtom.h handle that.) Static and dynamic atoms now store their chars in different ways: nsStaticAtom stores them inline, nsDynamicAtom has a pointer to separate storage. So `mString` and GetStringBuffer() move from nsAtom to nsDynamicAtom. The change to static atoms means they can be made constexpr and stored in read-only memory instead of on the heap. On 64-bit this reduces the per-process overhead by 16 bytes; on 32-bit the saving is 12 bytes. (Further reductions will be possible in follow-up patches.) The increased use of constexpr required multiple workarounds for MSVC. - Multiple uses of MOZ_{PUSH,POP}_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING to disable warnings about (well-defined!) overflow of unsigned integer arithmetic. - The use of -Zc:externConstexpr on all files defining static atoms, to make MSVC follow the C++ standard(!) and let constexpr variables have external linkage. - The use of -constexpr:steps300000 to increase the number of operations allowed in a constexpr value, in order to handle gGkAtoms, which requires hashing ~2,500 atom strings. The patch also changes how HTML5 atoms are handled. They are now treated as dynamic atoms, i.e. we have "dynamic normal" atoms and "dynamic HTML5 atoms", and "dynamic atoms" covers both cases, and both are represented via nsDynamicAtom. The main difference between the two kinds is that dynamic HTML5 atoms still aren't allowed to be used in various operations, most notably AddRef()/Release(). All this also required moving nsDynamicAtom into the header file. There is a slight performance cost to all these changes: now that nsStaticAtom and nsDynamicAtom store their chars in different ways, a conditional branch is required in the following functions: Equals(), GetUTF16String(), WeakAtom::as_slice(). Finally, in about:memory the "explicit/atoms/static/atom-objects" value is no longer needed, because that memory is static instead of heap-allocated. MozReview-Commit-ID: 4AxPv05ngZy
This commit is contained in:
parent
1c6665e18b
commit
bac452f9ad
@ -223,7 +223,8 @@ public:
|
||||
} else {
|
||||
// Dynamic atoms always have a string buffer and never have 0 length,
|
||||
// because nsGkAtoms::_empty is a static atom.
|
||||
SetKnownLiveStringBuffer(aAtom->GetStringBuffer(), aAtom->GetLength());
|
||||
SetKnownLiveStringBuffer(
|
||||
aAtom->AsDynamic()->GetStringBuffer(), aAtom->GetLength());
|
||||
}
|
||||
} else if (aNullHandling == eTreatNullAsNull) {
|
||||
SetNull();
|
||||
|
@ -305,6 +305,7 @@ whitelist-types = [
|
||||
"nsCursorImage",
|
||||
"nsFont",
|
||||
"nsAtom",
|
||||
"nsDynamicAtom",
|
||||
"nsMainThreadPtrHandle",
|
||||
"nsMainThreadPtrHolder",
|
||||
"nsMargin",
|
||||
|
@ -186,7 +186,6 @@ UNIFIED_SOURCES += [
|
||||
'MediaQueryList.cpp',
|
||||
'nsAnimationManager.cpp',
|
||||
'nsComputedDOMStyle.cpp',
|
||||
'nsCSSAnonBoxes.cpp',
|
||||
'nsCSSCounterStyleRule.cpp',
|
||||
'nsCSSFontFaceRule.cpp',
|
||||
'nsCSSKeywords.cpp',
|
||||
@ -241,6 +240,7 @@ UNIFIED_SOURCES += [
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'nsCSSAnonBoxes.cpp',
|
||||
# Both nsCSSPseudoElements.cpp and nsCSSPseudoClasses.cpp defined a
|
||||
# 'mozPlaceholder' static atom.
|
||||
'nsCSSPseudoElements.cpp',
|
||||
@ -248,6 +248,11 @@ SOURCES += [
|
||||
# windows.h.
|
||||
'nsLayoutStylesheetCache.cpp',
|
||||
]
|
||||
if CONFIG['CC_TYPE'] == 'msvc':
|
||||
# Needed for gCSSAnonBoxAtoms.
|
||||
SOURCES['nsCSSAnonBoxes.cpp'].flags += ['-Zc:externConstexpr']
|
||||
# Needed for gCSSPseudoElementAtoms.
|
||||
SOURCES['nsCSSPseudoElements.cpp'].flags += ['-Zc:externConstexpr']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
|
@ -13,12 +13,28 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#define CSS_ANON_BOX(name_, value_) \
|
||||
NS_STATIC_ATOM_SUBCLASS_DEFN(nsICSSAnonBoxPseudo, nsCSSAnonBoxes, name_)
|
||||
#include "nsCSSAnonBoxList.h"
|
||||
#undef CSS_ANON_BOX
|
||||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
#define CSS_ANON_BOX(name_, value_) NS_STATIC_ATOM_BUFFER(name_, value_)
|
||||
MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
extern constexpr CSSAnonBoxAtoms gCSSAnonBoxAtoms = {
|
||||
#define CSS_ANON_BOX(name_, value_) \
|
||||
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
|
||||
};
|
||||
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mozilla
|
||||
|
||||
#define CSS_ANON_BOX(name_, value_) \
|
||||
NS_STATIC_ATOM_SUBCLASS_DEFN_PTR(nsICSSAnonBoxPseudo, nsCSSAnonBoxes, name_)
|
||||
#include "nsCSSAnonBoxList.h"
|
||||
#undef CSS_ANON_BOX
|
||||
|
||||
@ -26,13 +42,15 @@ static const nsStaticAtomSetup sCSSAnonBoxAtomSetup[] = {
|
||||
// Put the non-inheriting anon boxes first, so we can index into them easily.
|
||||
#define CSS_ANON_BOX(name_, value_) /* nothing */
|
||||
#define CSS_NON_INHERITING_ANON_BOX(name_, value_) \
|
||||
NS_STATIC_ATOM_SUBCLASS_SETUP(nsCSSAnonBoxes, name_)
|
||||
NS_STATIC_ATOM_SUBCLASS_SETUP( \
|
||||
mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
|
||||
#include "nsCSSAnonBoxList.h"
|
||||
#undef CSS_NON_INHERITING_ANON_BOX
|
||||
#undef CSS_ANON_BOX
|
||||
|
||||
#define CSS_ANON_BOX(name_, value_) \
|
||||
NS_STATIC_ATOM_SUBCLASS_SETUP(nsCSSAnonBoxes, name_)
|
||||
NS_STATIC_ATOM_SUBCLASS_SETUP( \
|
||||
mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
|
||||
#define CSS_NON_INHERITING_ANON_BOX(name_, value_) /* nothing */
|
||||
#include "nsCSSAnonBoxList.h"
|
||||
#undef CSS_NON_INHERITING_ANON_BOX
|
||||
|
@ -16,6 +16,25 @@
|
||||
// require an atom from this atom list.
|
||||
class nsICSSAnonBoxPseudo : public nsAtom {};
|
||||
|
||||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
struct CSSAnonBoxAtoms
|
||||
{
|
||||
#define CSS_ANON_BOX(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
|
||||
#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
|
||||
};
|
||||
|
||||
extern const CSSAnonBoxAtoms gCSSAnonBoxAtoms;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mozilla
|
||||
|
||||
class nsCSSAnonBoxes {
|
||||
public:
|
||||
|
||||
@ -32,7 +51,7 @@ public:
|
||||
}
|
||||
|
||||
#define CSS_ANON_BOX(name_, value_) \
|
||||
NS_STATIC_ATOM_SUBCLASS_DECL(nsICSSAnonBoxPseudo, name_)
|
||||
NS_STATIC_ATOM_SUBCLASS_DECL_PTR(nsICSSAnonBoxPseudo, name_)
|
||||
#include "nsCSSAnonBoxList.h"
|
||||
#undef CSS_ANON_BOX
|
||||
|
||||
|
@ -28,28 +28,55 @@ using namespace mozilla;
|
||||
#include "nsCSSPseudoClassList.h"
|
||||
#undef CSS_PSEUDO_CLASS
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct CSSPseudoClassAtoms
|
||||
{
|
||||
#define CSS_PSEUDO_CLASS(name_, value_, flags_, pref_) \
|
||||
NS_STATIC_ATOM_DECL_STRING(name_, value_)
|
||||
#include "nsCSSPseudoClassList.h"
|
||||
#undef CSS_PSEUDO_CLASS
|
||||
|
||||
#define CSS_PSEUDO_CLASS(name_, value_, flags_, pref_) \
|
||||
NS_STATIC_ATOM_DECL_ATOM(name_)
|
||||
#include "nsCSSPseudoClassList.h"
|
||||
#undef CSS_PSEUDO_CLASS
|
||||
};
|
||||
|
||||
MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
static constexpr CSSPseudoClassAtoms sCSSPseudoClassAtoms = {
|
||||
#define CSS_PSEUDO_CLASS(name_, value_, flags_, pref_) \
|
||||
NS_STATIC_ATOM_INIT_STRING(value_)
|
||||
#include "nsCSSPseudoClassList.h"
|
||||
#undef CSS_PSEUDO_CLASS
|
||||
|
||||
#define CSS_PSEUDO_CLASS(name_, value_, flags_, pref_) \
|
||||
NS_STATIC_ATOM_INIT_ATOM(CSSPseudoClassAtoms, name_, value_)
|
||||
#include "nsCSSPseudoClassList.h"
|
||||
#undef CSS_PSEUDO_CLASS
|
||||
};
|
||||
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class CSSPseudoClassAtoms
|
||||
{
|
||||
public:
|
||||
#define CSS_PSEUDO_CLASS(name_, value_, flags_, pref_) \
|
||||
NS_STATIC_ATOM_DECL(name_)
|
||||
NS_STATIC_ATOM_DECL_PTR(name_)
|
||||
#include "nsCSSPseudoClassList.h"
|
||||
#undef CSS_PSEUDO_CLASS
|
||||
};
|
||||
|
||||
#define CSS_PSEUDO_CLASS(name_, value_, flags_, pref_) \
|
||||
NS_STATIC_ATOM_DEFN(CSSPseudoClassAtoms, name_)
|
||||
#include "nsCSSPseudoClassList.h"
|
||||
#undef CSS_PSEUDO_CLASS
|
||||
|
||||
#define CSS_PSEUDO_CLASS(name_, value_, flags_, pref_) \
|
||||
NS_STATIC_ATOM_BUFFER(name_, value_)
|
||||
NS_STATIC_ATOM_DEFN_PTR(CSSPseudoClassAtoms, name_)
|
||||
#include "nsCSSPseudoClassList.h"
|
||||
#undef CSS_PSEUDO_CLASS
|
||||
|
||||
static const nsStaticAtomSetup sCSSPseudoClassAtomSetup[] = {
|
||||
#define CSS_PSEUDO_CLASS(name_, value_, flags_, pref_) \
|
||||
NS_STATIC_ATOM_SETUP(CSSPseudoClassAtoms, name_)
|
||||
NS_STATIC_ATOM_SETUP( \
|
||||
::detail::sCSSPseudoClassAtoms, CSSPseudoClassAtoms, name_)
|
||||
#include "nsCSSPseudoClassList.h"
|
||||
#undef CSS_PSEUDO_CLASS
|
||||
};
|
||||
|
@ -16,20 +16,37 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
|
||||
NS_STATIC_ATOM_BUFFER(name_, value_)
|
||||
#include "nsCSSPseudoElementList.h"
|
||||
#undef CSS_PSEUDO_ELEMENT
|
||||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
extern constexpr CSSPseudoElementAtoms gCSSPseudoElementAtoms = {
|
||||
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
|
||||
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
|
||||
};
|
||||
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mozilla
|
||||
|
||||
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
|
||||
NS_STATIC_ATOM_SUBCLASS_DEFN(nsICSSPseudoElement, nsCSSPseudoElements, name_)
|
||||
NS_STATIC_ATOM_SUBCLASS_DEFN_PTR( \
|
||||
nsICSSPseudoElement, 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(nsCSSPseudoElements, name_)
|
||||
NS_STATIC_ATOM_SUBCLASS_SETUP( \
|
||||
detail::gCSSPseudoElementAtoms, nsCSSPseudoElements, name_)
|
||||
#include "nsCSSPseudoElementList.h"
|
||||
#undef CSS_PSEUDO_ELEMENT
|
||||
};
|
||||
|
@ -79,6 +79,25 @@ enum class CSSPseudoElementType : CSSPseudoElementTypeBase {
|
||||
MAX
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct CSSPseudoElementAtoms
|
||||
{
|
||||
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
|
||||
NS_STATIC_ATOM_DECL_STRING(name_, value_)
|
||||
#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
|
||||
};
|
||||
|
||||
extern const CSSPseudoElementAtoms gCSSPseudoElementAtoms;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// Empty class derived from nsAtom so that function signatures can
|
||||
@ -105,8 +124,8 @@ public:
|
||||
return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_IS_CSS2);
|
||||
}
|
||||
|
||||
#define CSS_PSEUDO_ELEMENT(_name, _value, _flags) \
|
||||
NS_STATIC_ATOM_SUBCLASS_DECL(nsICSSPseudoElement, _name)
|
||||
#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
|
||||
NS_STATIC_ATOM_SUBCLASS_DECL_PTR(nsICSSPseudoElement, name_)
|
||||
#include "nsCSSPseudoElementList.h"
|
||||
#undef CSS_PSEUDO_ELEMENT
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
nsHtml5AtomEntry::nsHtml5AtomEntry(KeyTypePointer aStr)
|
||||
: nsStringHashKey(aStr)
|
||||
, mAtom(new nsAtom(nsAtom::AtomKind::HTML5Atom, *aStr, 0))
|
||||
, mAtom(new nsDynamicAtom(*aStr))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ public:
|
||||
inline nsAtom* GetAtom() { return mAtom; }
|
||||
|
||||
private:
|
||||
nsAtom* mAtom;
|
||||
nsDynamicAtom* mAtom;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -103,8 +103,8 @@
|
||||
present.images = true;
|
||||
} else if (aPath.search(/^explicit\/xpti-working-set$/) >= 0) {
|
||||
present.xptiWorkingSet = true;
|
||||
} else if (aPath.search(/^explicit\/atoms\/static\/atom-objects$/) >= 0) {
|
||||
present.staticAtomObjects = true;
|
||||
} else if (aPath.search(/^explicit\/atoms\/dynamic\/atom-objects$/) >= 0) {
|
||||
present.dynamicAtomObjects = true;
|
||||
} else if (/\[System Principal\].*this-is-a-sandbox-name/.test(aPath)) {
|
||||
// A system compartment with a location (such as a sandbox) should
|
||||
// show that location.
|
||||
@ -261,7 +261,7 @@
|
||||
ok(present.places, "places is present");
|
||||
ok(present.images, "images is present");
|
||||
ok(present.xptiWorkingSet, "xpti-working-set is present");
|
||||
ok(present.staticAtomObjects, "static/atom-objects is present");
|
||||
ok(present.dynamicAtomObjects, "dynamic/atom-objects is present");
|
||||
ok(present.sandboxLocation, "sandbox locations are present");
|
||||
ok(present.bigString, "large string is present");
|
||||
ok(present.smallString1, "small string 1 is present");
|
||||
|
@ -1420,11 +1420,6 @@ public:
|
||||
"explicit/atoms/table", KIND_HEAP, UNITS_BYTES, sizes.mTable,
|
||||
"Memory used by the atom table.");
|
||||
|
||||
MOZ_COLLECT_REPORT(
|
||||
"explicit/atoms/static/atom-objects", KIND_HEAP, UNITS_BYTES,
|
||||
sizes.mStaticAtomObjects,
|
||||
"Memory used by static atom objects.");
|
||||
|
||||
MOZ_COLLECT_REPORT(
|
||||
"explicit/atoms/dynamic/atom-objects", KIND_HEAP, UNITS_BYTES,
|
||||
sizes.mDynamicAtomObjects,
|
||||
|
@ -118,10 +118,15 @@ UNIFIED_SOURCES += [
|
||||
'Tokenizer.cpp',
|
||||
]
|
||||
|
||||
# XXX: will be moved to UNIFIED_SOURCES in the next patch
|
||||
SOURCES += [
|
||||
'nsGkAtoms.cpp',
|
||||
]
|
||||
if CONFIG['CC_TYPE'] == 'msvc':
|
||||
# Needed for gGkAtoms.
|
||||
SOURCES['nsGkAtoms.cpp'].flags += [
|
||||
'-constexpr:steps300000',
|
||||
'-Zc:externConstexpr',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'nsINIProcessor.js',
|
||||
|
@ -10,27 +10,49 @@
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
|
||||
namespace mozilla {
|
||||
struct AtomsSizes;
|
||||
}
|
||||
|
||||
class nsStaticAtom;
|
||||
class nsDynamicAtom;
|
||||
|
||||
// This class encompasses both static and dynamic atoms.
|
||||
//
|
||||
// - In places where static and dynamic atoms can be used, use RefPtr<nsAtom>.
|
||||
// This is by far the most common case. (The exception to this is the HTML5
|
||||
// parser, which does its own weird thing, and uses non-refcounted dynamic
|
||||
// atoms.)
|
||||
//
|
||||
// - In places where only static atoms can appear, use nsStaticAtom* to avoid
|
||||
// unnecessary refcounting. This is a moderately common case.
|
||||
//
|
||||
// - In places where only dynamic atoms can appear, it doesn't matter much
|
||||
// whether you use RefPtr<nsAtom> or RefPtr<nsDynamicAtom>. This is an
|
||||
// extremely rare case.
|
||||
//
|
||||
class nsAtom
|
||||
{
|
||||
public:
|
||||
void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
mozilla::AtomsSizes& aSizes) const;
|
||||
|
||||
// Dynamic HTML5 atoms are just like vanilla dynamic atoms, but we disallow
|
||||
// various operations, the most important of which is AddRef/Release.
|
||||
// XXX: we'd like to get rid of dynamic HTML5 atoms. See bug 1392185 for
|
||||
// details.
|
||||
enum class AtomKind : uint8_t {
|
||||
DynamicAtom = 0,
|
||||
StaticAtom = 1,
|
||||
HTML5Atom = 2,
|
||||
Static = 0,
|
||||
DynamicNormal = 1,
|
||||
DynamicHTML5 = 2,
|
||||
};
|
||||
|
||||
bool Equals(char16ptr_t aString, uint32_t aLength) const
|
||||
{
|
||||
return mLength == aLength &&
|
||||
memcmp(mString, aString, mLength * sizeof(char16_t)) == 0;
|
||||
memcmp(GetUTF16String(), aString, mLength * sizeof(char16_t)) == 0;
|
||||
}
|
||||
|
||||
bool Equals(const nsAString& aString) const
|
||||
@ -40,26 +62,28 @@ public:
|
||||
|
||||
AtomKind Kind() const { return static_cast<AtomKind>(mKind); }
|
||||
|
||||
bool IsDynamic() const { return Kind() == AtomKind::DynamicAtom; }
|
||||
bool IsHTML5() const { return Kind() == AtomKind::HTML5Atom; }
|
||||
bool IsStatic() const { return Kind() == AtomKind::StaticAtom; }
|
||||
bool IsStatic() const { return Kind() == AtomKind::Static; }
|
||||
bool IsDynamic() const
|
||||
{
|
||||
return Kind() == AtomKind::DynamicNormal ||
|
||||
Kind() == AtomKind::DynamicHTML5;
|
||||
}
|
||||
bool IsDynamicHTML5() const
|
||||
{
|
||||
return Kind() == AtomKind::DynamicHTML5;
|
||||
}
|
||||
|
||||
char16ptr_t GetUTF16String() const { return mString; }
|
||||
const nsStaticAtom* AsStatic() const;
|
||||
const nsDynamicAtom* AsDynamic() const;
|
||||
nsDynamicAtom* AsDynamic();
|
||||
|
||||
char16ptr_t GetUTF16String() const;
|
||||
|
||||
uint32_t GetLength() const { return mLength; }
|
||||
|
||||
void ToString(nsAString& aString) const;
|
||||
void ToUTF8String(nsACString& aString) const;
|
||||
|
||||
// This is not valid for static atoms. The caller must *not* mutate the
|
||||
// string buffer, otherwise all hell will break loose.
|
||||
nsStringBuffer* GetStringBuffer() const
|
||||
{
|
||||
// See the comment on |mString|'s declaration.
|
||||
MOZ_ASSERT(IsDynamic() || IsHTML5());
|
||||
return nsStringBuffer::FromData(const_cast<char16_t*>(mString));
|
||||
}
|
||||
|
||||
// A hashcode that is better distributed than the actual atom pointer, for
|
||||
// use in situations that need a well-distributed hashcode. It's called hash()
|
||||
// rather than Hash() so we can use mozilla::BloomFilter<N, nsAtom>, because
|
||||
@ -67,7 +91,7 @@ public:
|
||||
//
|
||||
uint32_t hash() const
|
||||
{
|
||||
MOZ_ASSERT(!IsHTML5());
|
||||
MOZ_ASSERT(!IsDynamicHTML5());
|
||||
return mHash;
|
||||
}
|
||||
|
||||
@ -78,37 +102,34 @@ public:
|
||||
|
||||
typedef mozilla::TrueType HasThreadSafeRefCnt;
|
||||
|
||||
private:
|
||||
friend class nsAtomTable;
|
||||
friend class nsAtomSubTable;
|
||||
friend class nsHtml5AtomEntry;
|
||||
|
||||
protected:
|
||||
// Used by nsDynamicAtom and directly (by nsHtml5AtomEntry) for HTML5 atoms.
|
||||
nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash);
|
||||
|
||||
// Used by nsStaticAtom.
|
||||
nsAtom(const char16_t* aString, uint32_t aLength, uint32_t aHash);
|
||||
constexpr nsAtom(const char16_t* aStr, uint32_t aLength)
|
||||
: mLength(aLength)
|
||||
, mKind(static_cast<uint32_t>(nsAtom::AtomKind::Static))
|
||||
, mHash(mozilla::ConstExprHashString(aStr))
|
||||
{}
|
||||
|
||||
~nsAtom();
|
||||
// Used by nsDynamicAtom.
|
||||
nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash)
|
||||
: mLength(aString.Length())
|
||||
, mKind(static_cast<uint32_t>(aKind))
|
||||
, mHash(aHash)
|
||||
{
|
||||
MOZ_ASSERT(aKind == AtomKind::DynamicNormal ||
|
||||
aKind == AtomKind::DynamicHTML5);
|
||||
}
|
||||
|
||||
~nsAtom() = default;
|
||||
|
||||
const uint32_t mLength:30;
|
||||
const uint32_t mKind:2; // nsAtom::AtomKind
|
||||
const uint32_t mHash;
|
||||
// WARNING! For static atoms, this is a pointer to a static char buffer. For
|
||||
// non-static atoms it points to the chars in an nsStringBuffer. This means
|
||||
// that nsStringBuffer::FromData(mString) calls are only valid for non-static
|
||||
// atoms.
|
||||
const char16_t* const mString;
|
||||
};
|
||||
|
||||
// A trivial subclass of nsAtom that can be used for known static atoms. The
|
||||
// main advantage of this class is that it doesn't require refcounting, so you
|
||||
// can use |nsStaticAtom*| in contrast with |RefPtr<nsAtom>|.
|
||||
//
|
||||
// This class would be |final| if it wasn't for nsICSSAnonBoxPseudo and
|
||||
// nsICSSPseudoElement, which are trivial subclasses used to ensure only
|
||||
// certain atoms are passed to certain functions.
|
||||
// certain static atoms are passed to certain functions.
|
||||
class nsStaticAtom : public nsAtom
|
||||
{
|
||||
public:
|
||||
@ -117,17 +138,64 @@ public:
|
||||
MozExternalRefCountType AddRef() = delete;
|
||||
MozExternalRefCountType Release() = delete;
|
||||
|
||||
constexpr nsStaticAtom(const char16_t* aStr, uint32_t aLength,
|
||||
uint32_t aStringOffset)
|
||||
: nsAtom(aStr, aLength)
|
||||
, mStringOffset(aStringOffset)
|
||||
{}
|
||||
|
||||
const char16_t* String() const
|
||||
{
|
||||
return reinterpret_cast<const char16_t*>(uintptr_t(this) - mStringOffset);
|
||||
}
|
||||
|
||||
already_AddRefed<nsAtom> ToAddRefed() {
|
||||
return already_AddRefed<nsAtom>(static_cast<nsAtom*>(this));
|
||||
}
|
||||
|
||||
private:
|
||||
friend class nsAtomTable;
|
||||
// This is an offset to the string chars, which must be at a lower address in
|
||||
// memory. This should be achieved by using the macros in nsStaticAtom.h.
|
||||
uint32_t mStringOffset;
|
||||
};
|
||||
|
||||
// Construction is done entirely by |friend|s.
|
||||
nsStaticAtom(const char16_t* aString, uint32_t aLength, uint32_t aHash)
|
||||
: nsAtom(aString, aLength, aHash)
|
||||
{}
|
||||
class nsDynamicAtom : public nsAtom
|
||||
{
|
||||
public:
|
||||
// We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
|
||||
// of this type is special.
|
||||
MozExternalRefCountType AddRef();
|
||||
MozExternalRefCountType Release();
|
||||
|
||||
~nsDynamicAtom();
|
||||
|
||||
const char16_t* String() const { return mString; }
|
||||
|
||||
// The caller must *not* mutate the string buffer, otherwise all hell will
|
||||
// break loose.
|
||||
nsStringBuffer* GetStringBuffer() const
|
||||
{
|
||||
// See the comment on |mString|'s declaration.
|
||||
MOZ_ASSERT(IsDynamic());
|
||||
return nsStringBuffer::FromData(const_cast<char16_t*>(mString));
|
||||
}
|
||||
|
||||
private:
|
||||
friend class nsAtomTable;
|
||||
friend class nsAtomSubTable;
|
||||
// XXX: we'd like to remove nsHtml5AtomEntry. See bug 1392185.
|
||||
friend class nsHtml5AtomEntry;
|
||||
|
||||
// Construction is done by |friend|s.
|
||||
// The first constructor is for dynamic normal atoms, the second is for
|
||||
// dynamic HTML5 atoms.
|
||||
nsDynamicAtom(const nsAString& aString, uint32_t aHash);
|
||||
explicit nsDynamicAtom(const nsAString& aString);
|
||||
|
||||
mozilla::ThreadSafeAutoRefCnt mRefCnt;
|
||||
// Note: this points to the chars in an nsStringBuffer, which is obtained
|
||||
// with nsStringBuffer::FromData(mString).
|
||||
const char16_t* const mString;
|
||||
};
|
||||
|
||||
// The four forms of NS_Atomize (for use with |RefPtr<nsAtom>|) return the
|
||||
|
@ -37,10 +37,8 @@
|
||||
// table, removing and deleting dynamic atoms with refcount zero. This allows
|
||||
// us to avoid acquiring the atom table lock during normal refcounting.
|
||||
//
|
||||
// - Static: the atom itself is heap allocated, but it points to a static
|
||||
// nsStringBuffer. |gAtomTable| effectively owns static atoms, because such
|
||||
// atoms ignore all AddRef/Release calls, which ensures they stay alive until
|
||||
// |gAtomTable| itself is destroyed whereupon they are explicitly deleted.
|
||||
// - Static: both the atom and its chars are statically allocated and
|
||||
// immutable, so it ignores all AddRef/Release calls.
|
||||
//
|
||||
// Note that gAtomTable is used on multiple threads, and has internal
|
||||
// synchronization.
|
||||
@ -65,34 +63,6 @@ enum class GCKind {
|
||||
// See nsAtom::AddRef() and nsAtom::Release().
|
||||
static Atomic<int32_t, ReleaseAcquire> gUnusedAtomCount(0);
|
||||
|
||||
// Dynamic atoms need a ref count; this class adds that to nsAtom.
|
||||
class nsDynamicAtom : public nsAtom
|
||||
{
|
||||
public:
|
||||
// We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
|
||||
// of this type is special.
|
||||
MozExternalRefCountType AddRef();
|
||||
MozExternalRefCountType Release();
|
||||
|
||||
static nsDynamicAtom* As(nsAtom* aAtom)
|
||||
{
|
||||
MOZ_ASSERT(aAtom->IsDynamic());
|
||||
return static_cast<nsDynamicAtom*>(aAtom);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class nsAtomTable;
|
||||
friend class nsAtomSubTable;
|
||||
|
||||
// Construction is done by |friend|s.
|
||||
nsDynamicAtom(const nsAString& aString, uint32_t aHash)
|
||||
: nsAtom(AtomKind::DynamicAtom, aString, aHash)
|
||||
, mRefCnt(1)
|
||||
{}
|
||||
|
||||
mozilla::ThreadSafeAutoRefCnt mRefCnt;
|
||||
};
|
||||
|
||||
static char16_t*
|
||||
FromStringBuffer(const nsAString& aString)
|
||||
{
|
||||
@ -121,40 +91,50 @@ FromStringBuffer(const nsAString& aString)
|
||||
return str;
|
||||
}
|
||||
|
||||
// This constructor is for dynamic atoms and HTML5 atoms.
|
||||
nsAtom::nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash)
|
||||
: mLength(aString.Length())
|
||||
, mKind(static_cast<uint32_t>(aKind))
|
||||
, mHash(aHash)
|
||||
nsDynamicAtom::nsDynamicAtom(const nsAString& aString, uint32_t aHash)
|
||||
: nsAtom(AtomKind::DynamicNormal, aString, aHash)
|
||||
, mRefCnt(1)
|
||||
, mString(FromStringBuffer(aString))
|
||||
{
|
||||
MOZ_ASSERT(aKind == AtomKind::DynamicAtom || aKind == AtomKind::HTML5Atom);
|
||||
|
||||
MOZ_ASSERT_IF(!IsHTML5(), mHash == HashString(mString, mLength));
|
||||
MOZ_ASSERT(mHash == HashString(mString, mLength));
|
||||
|
||||
MOZ_ASSERT(mString[mLength] == char16_t(0), "null terminated");
|
||||
MOZ_ASSERT(Equals(aString), "correct data");
|
||||
}
|
||||
|
||||
// This constructor is for static atoms.
|
||||
nsAtom::nsAtom(const char16_t* aString, uint32_t aLength, uint32_t aHash)
|
||||
: mLength(aLength)
|
||||
, mKind(static_cast<uint32_t>(AtomKind::StaticAtom))
|
||||
, mHash(aHash)
|
||||
, mString(const_cast<char16_t*>(aString))
|
||||
nsDynamicAtom::nsDynamicAtom(const nsAString& aString)
|
||||
: nsAtom(AtomKind::DynamicHTML5, aString, 0)
|
||||
, mRefCnt(1)
|
||||
, mString(FromStringBuffer(aString))
|
||||
{
|
||||
MOZ_ASSERT(mHash == HashString(mString, mLength));
|
||||
|
||||
MOZ_ASSERT(mString[mLength] == char16_t(0), "null terminated");
|
||||
MOZ_ASSERT(NS_strlen(mString) == mLength, "correct storage");
|
||||
MOZ_ASSERT(Equals(aString), "correct data");
|
||||
}
|
||||
|
||||
nsAtom::~nsAtom()
|
||||
nsDynamicAtom::~nsDynamicAtom()
|
||||
{
|
||||
if (!IsStatic()) {
|
||||
MOZ_ASSERT(IsDynamic() || IsHTML5());
|
||||
GetStringBuffer()->Release();
|
||||
}
|
||||
GetStringBuffer()->Release();
|
||||
}
|
||||
|
||||
const nsStaticAtom*
|
||||
nsAtom::AsStatic() const
|
||||
{
|
||||
MOZ_ASSERT(IsStatic());
|
||||
return static_cast<const nsStaticAtom*>(this);
|
||||
}
|
||||
|
||||
const nsDynamicAtom*
|
||||
nsAtom::AsDynamic() const
|
||||
{
|
||||
MOZ_ASSERT(IsDynamic());
|
||||
return static_cast<const nsDynamicAtom*>(this);
|
||||
}
|
||||
|
||||
nsDynamicAtom*
|
||||
nsAtom::AsDynamic()
|
||||
{
|
||||
MOZ_ASSERT(IsDynamic());
|
||||
return static_cast<nsDynamicAtom*>(this);
|
||||
}
|
||||
|
||||
void
|
||||
@ -165,41 +145,55 @@ nsAtom::ToString(nsAString& aString) const
|
||||
// AssignLiteral() lets us assign without copying. This isn't a string
|
||||
// literal, but it's a static atom and thus has an unbounded lifetime,
|
||||
// which is what's important.
|
||||
aString.AssignLiteral(mString, mLength);
|
||||
aString.AssignLiteral(AsStatic()->String(), mLength);
|
||||
} else {
|
||||
GetStringBuffer()->ToString(mLength, aString);
|
||||
AsDynamic()->GetStringBuffer()->ToString(mLength, aString);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAtom::ToUTF8String(nsACString& aBuf) const
|
||||
{
|
||||
MOZ_ASSERT(!IsHTML5(), "Called ToUTF8String() on an HTML5 atom");
|
||||
CopyUTF16toUTF8(nsDependentString(mString, mLength), aBuf);
|
||||
MOZ_ASSERT(!IsDynamicHTML5(),
|
||||
"Called ToUTF8String() on a dynamic HTML5 atom");
|
||||
CopyUTF16toUTF8(nsDependentString(GetUTF16String(), mLength), aBuf);
|
||||
}
|
||||
|
||||
void
|
||||
nsAtom::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, AtomsSizes& aSizes)
|
||||
const
|
||||
{
|
||||
MOZ_ASSERT(!IsHTML5(),
|
||||
"Called AddSizeOfIncludingThis() on an HTML5 atom");
|
||||
size_t thisSize = aMallocSizeOf(this);
|
||||
if (IsStatic()) {
|
||||
// String buffers pointed to by static atoms are in static memory, and so
|
||||
// are not measured here.
|
||||
aSizes.mStaticAtomObjects += thisSize;
|
||||
} else {
|
||||
aSizes.mDynamicAtomObjects += thisSize;
|
||||
MOZ_ASSERT(!IsDynamicHTML5(),
|
||||
"Called AddSizeOfIncludingThis() on a dynamic HTML5 atom");
|
||||
|
||||
// Static atoms are in static memory, and so are not measured here.
|
||||
if (IsDynamic()) {
|
||||
aSizes.mDynamicAtomObjects += aMallocSizeOf(this);
|
||||
aSizes.mDynamicUnsharedBuffers +=
|
||||
GetStringBuffer()->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
|
||||
AsDynamic()->GetStringBuffer()->SizeOfIncludingThisIfUnshared(
|
||||
aMallocSizeOf);
|
||||
}
|
||||
}
|
||||
|
||||
char16ptr_t
|
||||
nsAtom::GetUTF16String() const
|
||||
{
|
||||
return IsStatic() ? AsStatic()->String() : AsDynamic()->String();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
struct AtomTableKey
|
||||
{
|
||||
explicit AtomTableKey(const nsStaticAtom* aAtom)
|
||||
: mUTF16String(aAtom->String())
|
||||
, mUTF8String(nullptr)
|
||||
, mLength(aAtom->GetLength())
|
||||
, mHash(aAtom->hash())
|
||||
{
|
||||
MOZ_ASSERT(HashString(mUTF16String, mLength) == mHash);
|
||||
}
|
||||
|
||||
AtomTableKey(const char16_t* aUTF16String, uint32_t aLength,
|
||||
uint32_t* aHashOut)
|
||||
: mUTF16String(aUTF16String)
|
||||
@ -360,13 +354,7 @@ void
|
||||
nsAtomTable::AtomTableClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
|
||||
{
|
||||
auto entry = static_cast<AtomTableEntry*>(aEntry);
|
||||
nsAtom* atom = entry->mAtom;
|
||||
if (atom->IsStatic()) {
|
||||
// This case -- when the entry being cleared holds a static atom -- only
|
||||
// occurs when gAtomTable is destroyed, whereupon all static atoms within it
|
||||
// must be explicitly deleted.
|
||||
delete atom;
|
||||
}
|
||||
entry->mAtom = nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -510,10 +498,10 @@ nsAtomSubTable::GCLocked(GCKind aKind)
|
||||
}
|
||||
|
||||
nsAtom* atom = entry->mAtom;
|
||||
MOZ_ASSERT(!atom->IsHTML5());
|
||||
if (atom->IsDynamic() && nsDynamicAtom::As(atom)->mRefCnt == 0) {
|
||||
MOZ_ASSERT(!atom->IsDynamicHTML5());
|
||||
if (atom->IsDynamic() && atom->AsDynamic()->mRefCnt == 0) {
|
||||
i.Remove();
|
||||
delete atom;
|
||||
delete atom->AsDynamic();
|
||||
++removedCount;
|
||||
}
|
||||
#ifdef NS_FREE_PERMANENT_DATA
|
||||
@ -589,17 +577,17 @@ nsDynamicAtom::Release()
|
||||
MozExternalRefCountType
|
||||
nsAtom::AddRef()
|
||||
{
|
||||
MOZ_ASSERT(!IsHTML5(), "Attempt to AddRef an HTML5 atom");
|
||||
MOZ_ASSERT(!IsDynamicHTML5(), "Attempt to AddRef a dynamic HTML5 atom");
|
||||
|
||||
return IsStatic() ? 2 : nsDynamicAtom::As(this)->AddRef();
|
||||
return IsStatic() ? 2 : AsDynamic()->AddRef();
|
||||
}
|
||||
|
||||
MozExternalRefCountType
|
||||
nsAtom::Release()
|
||||
{
|
||||
MOZ_ASSERT(!IsHTML5(), "Attempt to Release an HTML5 atom");
|
||||
MOZ_ASSERT(!IsDynamicHTML5(), "Attempt to Release a dynamic HTML5 atom");
|
||||
|
||||
return IsStatic() ? 1 : nsDynamicAtom::As(this)->Release();
|
||||
return IsStatic() ? 1 : AsDynamic()->Release();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@ -666,20 +654,17 @@ nsAtomTable::RegisterStaticAtoms(const nsStaticAtomSetup* aSetup,
|
||||
MOZ_RELEASE_ASSERT(!gStaticAtomsDone, "Static atom insertion is finished!");
|
||||
|
||||
for (uint32_t i = 0; i < aCount; ++i) {
|
||||
const char16_t* string = aSetup[i].mString;
|
||||
const nsStaticAtom* atom = aSetup[i].mAtom;
|
||||
nsStaticAtom** atomp = aSetup[i].mAtomp;
|
||||
|
||||
MOZ_ASSERT(nsCRT::IsAscii(string));
|
||||
MOZ_ASSERT(nsCRT::IsAscii(atom->String()));
|
||||
MOZ_ASSERT(NS_strlen(atom->String()) == atom->GetLength());
|
||||
|
||||
uint32_t stringLen = NS_strlen(string);
|
||||
|
||||
uint32_t hash;
|
||||
AtomTableKey key(string, stringLen, &hash);
|
||||
AtomTableKey key(atom);
|
||||
nsAtomSubTable& table = SelectSubTable(key);
|
||||
MutexAutoLock lock(table.mLock);
|
||||
AtomTableEntry* he = table.Add(key);
|
||||
|
||||
nsStaticAtom* atom;
|
||||
if (he->mAtom) {
|
||||
// Disallow creating a dynamic atom, and then later, while the dynamic
|
||||
// atom is still alive, registering that same atom as a static atom. It
|
||||
@ -690,12 +675,11 @@ nsAtomTable::RegisterStaticAtoms(const nsStaticAtomSetup* aSetup,
|
||||
MOZ_CRASH_UNSAFE_PRINTF(
|
||||
"Static atom registration for %s should be pushed back", name.get());
|
||||
}
|
||||
atom = static_cast<nsStaticAtom*>(he->mAtom);
|
||||
// XXX: A duplicate static atom! Bug 1445113 will disallow this case.
|
||||
*atomp = static_cast<nsStaticAtom*>(he->mAtom);
|
||||
} else {
|
||||
atom = new nsStaticAtom(string, stringLen, hash);
|
||||
he->mAtom = atom;
|
||||
he->mAtom = *atomp = const_cast<nsStaticAtom*>(atom);
|
||||
}
|
||||
*atomp = atom;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,11 @@ namespace mozilla {
|
||||
struct AtomsSizes
|
||||
{
|
||||
size_t mTable;
|
||||
size_t mStaticAtomObjects;
|
||||
size_t mDynamicAtomObjects;
|
||||
size_t mDynamicUnsharedBuffers;
|
||||
|
||||
AtomsSizes()
|
||||
: mTable(0)
|
||||
, mStaticAtomObjects(0)
|
||||
, mDynamicAtomObjects(0)
|
||||
, mDynamicUnsharedBuffers(0)
|
||||
{}
|
||||
|
@ -5,18 +5,33 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStaticAtom.h"
|
||||
|
||||
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DEFN(nsGkAtoms, name_)
|
||||
#include "nsGkAtomList.h"
|
||||
#undef GK_ATOM
|
||||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_BUFFER(name_, value_)
|
||||
MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
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
|
||||
};
|
||||
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mozilla
|
||||
|
||||
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DEFN_PTR(nsGkAtoms, name_)
|
||||
#include "nsGkAtomList.h"
|
||||
#undef GK_ATOM
|
||||
|
||||
static const nsStaticAtomSetup sGkAtomSetup[] = {
|
||||
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_SETUP(nsGkAtoms, name_)
|
||||
#define GK_ATOM(name_, value_) \
|
||||
NS_STATIC_ATOM_SETUP(mozilla::detail::gGkAtoms, nsGkAtoms, name_)
|
||||
#include "nsGkAtomList.h"
|
||||
#undef GK_ATOM
|
||||
};
|
||||
|
@ -7,14 +7,34 @@
|
||||
#ifndef nsGkAtoms_h___
|
||||
#define nsGkAtoms_h___
|
||||
|
||||
#include "nsAtom.h"
|
||||
#include "nsStaticAtom.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
struct GkAtoms
|
||||
{
|
||||
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
|
||||
#include "nsGkAtomList.h"
|
||||
#undef GK_ATOM
|
||||
|
||||
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
|
||||
#include "nsGkAtomList.h"
|
||||
#undef GK_ATOM
|
||||
};
|
||||
|
||||
extern const GkAtoms gGkAtoms;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mozilla
|
||||
|
||||
class nsGkAtoms
|
||||
{
|
||||
public:
|
||||
static void RegisterStaticAtoms();
|
||||
|
||||
#define GK_ATOM(_name, _value) NS_STATIC_ATOM_DECL(_name)
|
||||
#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(name_)
|
||||
#include "nsGkAtomList.h"
|
||||
#undef GK_ATOM
|
||||
};
|
||||
|
@ -20,32 +20,87 @@
|
||||
// MY_ATOM(two, "two")
|
||||
// MY_ATOM(three, "three")
|
||||
//
|
||||
// The code defining the static atoms might look like this:
|
||||
// The code defining the static atoms should look something like this:
|
||||
//
|
||||
// class MyAtoms {
|
||||
// public:
|
||||
// #define MY_ATOM(_name, _value) NS_STATIC_ATOM_DECL(_name)
|
||||
// ====> 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
|
||||
// };
|
||||
//
|
||||
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DEFN(MyAtoms, name_)
|
||||
// #include "MyAtomList.h"
|
||||
// #undef MY_ATOM
|
||||
// extern const MyAtoms gMyAtoms;
|
||||
//
|
||||
// #define MY_ATOM(name_, value_) NS_STATIC_ATOM_BUFFER(name_, value_)
|
||||
// } // 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(MyAtoms, name_)
|
||||
// #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:
|
||||
//
|
||||
// class MyAtoms
|
||||
// ====> MyAtoms.h <====
|
||||
//
|
||||
// // A `detail` namespace is used because the things within it aren't
|
||||
// // directly referenced by external users of these static atoms.
|
||||
// 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.
|
||||
// struct MyAtoms
|
||||
// {
|
||||
// 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;
|
||||
// };
|
||||
//
|
||||
// extern const MyAtoms gMyAtoms;
|
||||
//
|
||||
// } // namespace detail
|
||||
//
|
||||
// // This class holds the pointers to the individual atoms.
|
||||
// class nsMyAtoms
|
||||
// {
|
||||
// public:
|
||||
// static nsStaticAtom* one;
|
||||
@ -53,66 +108,100 @@
|
||||
// static nsStaticAtom* three;
|
||||
// };
|
||||
//
|
||||
// ====> MyAtoms.cpp <====
|
||||
//
|
||||
// // 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 = {
|
||||
// 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)),
|
||||
// };
|
||||
// MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
//
|
||||
// nsStaticAtom* MyAtoms::one;
|
||||
// nsStaticAtom* MyAtoms::two;
|
||||
// nsStaticAtom* MyAtoms::three;
|
||||
//
|
||||
// static const char16_t one_buffer[4] = u"one"; // plus a static_assert
|
||||
// static const char16_t two_buffer[4] = u"two"; // plus a static_assert
|
||||
// static const char16_t three_buffer[6] = u"three"; // plus a static_assert
|
||||
//
|
||||
// static const nsStaticAtomSetup sMyAtomSetup[] = {
|
||||
// { one_buffer, &MyAtoms::one },
|
||||
// { two_buffer, &MyAtoms::two },
|
||||
// { three_buffer, &MyAtoms::three },
|
||||
// { &detail::gMyAtoms.one_atom, &nsMyAtoms::one },
|
||||
// { &detail::gMyAtoms.two_atom, &nsMyAtoms::two },
|
||||
// { &detail::gMyAtoms.three_atom, &nsMyAtoms::three },
|
||||
// };
|
||||
//
|
||||
// When RegisterStaticAtoms(sMyAtomSetup) is called it iterates over
|
||||
// sMyAtomSetup[]. E.g. for the first atom it does roughly the following:
|
||||
// - MyAtoms::one = new nsStaticAtom(one_buffer)
|
||||
// - inserts MyAtoms::one into the atom table
|
||||
// - MyAtoms::one = one_atom
|
||||
// - inserts one_atom into the atom table
|
||||
|
||||
// The declaration of the pointer to the static atom, which must be within a
|
||||
// class.
|
||||
#define NS_STATIC_ATOM_DECL(name_) \
|
||||
// The declaration of the atom's string, which must be within the same `detail`
|
||||
// class as NS_STATIC_ATOM_DECL_ATOM.
|
||||
#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 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(type_, name_) \
|
||||
#define NS_STATIC_ATOM_SUBCLASS_DECL_PTR(type_, name_) \
|
||||
static type_* name_;
|
||||
|
||||
// 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(class_, name_) \
|
||||
nsStaticAtom* class_::name_;
|
||||
// The initialization of the atom's string, which must be within a `constexpr`
|
||||
// instance of the `detail` class.
|
||||
#define NS_STATIC_ATOM_INIT_STRING(value_) \
|
||||
u"" value_,
|
||||
|
||||
// Like NS_STATIC_ATOM_DEFN, but for sub-classes of nsStaticAtom.
|
||||
#define NS_STATIC_ATOM_SUBCLASS_DEFN(type_, class_, name_) \
|
||||
type_* class_::name_;
|
||||
|
||||
// The buffer of 16-bit chars that constitute the static atom.
|
||||
// The initialization of the static atom itself, which must be within a
|
||||
// `constexpr` instance of the `detail` class.
|
||||
//
|
||||
// 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, which is what is assigned.
|
||||
#define NS_STATIC_ATOM_BUFFER(name_, value_) \
|
||||
static const char16_t name_##_buffer[sizeof(value_)] = u"" value_; \
|
||||
static_assert(sizeof(value_[0]) == 1, "non-8-bit static atom literal");
|
||||
// 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)),
|
||||
|
||||
// The StaticAtomSetup. Used only during start-up.
|
||||
#define NS_STATIC_ATOM_SETUP(class_, name_) \
|
||||
{ name_##_buffer, &class_::name_ },
|
||||
// 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(class_, name_) \
|
||||
{ name_##_buffer, reinterpret_cast<nsStaticAtom**>(&class_::name_) },
|
||||
#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. They should never be
|
||||
// accessed directly other than from nsAtomTable.cpp.
|
||||
// NS_STATIC_ATOM_SETUP to initialize these structs.
|
||||
struct nsStaticAtomSetup
|
||||
{
|
||||
const char16_t* const mString;
|
||||
const nsStaticAtom* const mAtom;
|
||||
nsStaticAtom** const mAtomp;
|
||||
};
|
||||
|
||||
|
@ -98,7 +98,6 @@ UNIFIED_SOURCES += [
|
||||
'nsAnonymousTemporaryFile.cpp',
|
||||
'nsAppFileLocationProvider.cpp',
|
||||
'nsBinaryStream.cpp',
|
||||
'nsDirectoryService.cpp',
|
||||
'nsEscape.cpp',
|
||||
'nsInputStreamTee.cpp',
|
||||
'nsIOUtil.cpp',
|
||||
@ -122,6 +121,13 @@ UNIFIED_SOURCES += [
|
||||
'SpecialSystemDirectory.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'nsDirectoryService.cpp',
|
||||
]
|
||||
if CONFIG['CC_TYPE'] == 'msvc':
|
||||
# Needed for gDirectoryAtoms.
|
||||
SOURCES['nsDirectoryService.cpp'].flags += ['-Zc:externConstexpr']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
SOURCES += [
|
||||
'CocoaFileUtils.mm',
|
||||
|
@ -9,9 +9,9 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsDirectoryService.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsLocalFile.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStaticAtom.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
|
||||
@ -105,17 +105,34 @@ nsDirectoryService::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||
return gService->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DEFN(nsDirectoryService, name_)
|
||||
#include "nsDirectoryServiceAtomList.h"
|
||||
#undef DIR_ATOM
|
||||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_BUFFER(name_, value_)
|
||||
MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
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
|
||||
};
|
||||
MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mozilla
|
||||
|
||||
#define DIR_ATOM(name_, value_) \
|
||||
NS_STATIC_ATOM_DEFN_PTR(nsDirectoryService, name_)
|
||||
#include "nsDirectoryServiceAtomList.h"
|
||||
#undef DIR_ATOM
|
||||
|
||||
static const nsStaticAtomSetup sDirectoryServiceAtomSetup[] = {
|
||||
#define DIR_ATOM(name_, value_) \
|
||||
NS_STATIC_ATOM_SETUP(nsDirectoryService, name_)
|
||||
NS_STATIC_ATOM_SETUP( \
|
||||
mozilla::detail::gDirectoryAtoms, nsDirectoryService, name_)
|
||||
#include "nsDirectoryServiceAtomList.h"
|
||||
#undef DIR_ATOM
|
||||
};
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsAtom.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsStaticAtom.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
@ -20,6 +21,25 @@
|
||||
// CANNOT be used to GET a location
|
||||
#define NS_DIRECTORY_SERVICE_CID {0xf00152d0,0xb40b,0x11d3,{0x8c, 0x9c, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74}}
|
||||
|
||||
namespace mozilla {
|
||||
namespace detail {
|
||||
|
||||
struct DirectoryAtoms
|
||||
{
|
||||
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
|
||||
#include "nsDirectoryServiceAtomList.h"
|
||||
#undef DIR_ATOM
|
||||
|
||||
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
|
||||
#include "nsDirectoryServiceAtomList.h"
|
||||
#undef DIR_ATOM
|
||||
};
|
||||
|
||||
extern const DirectoryAtoms gDirectoryAtoms;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mozilla
|
||||
|
||||
class nsDirectoryService final
|
||||
: public nsIDirectoryService
|
||||
, public nsIProperties
|
||||
@ -55,7 +75,7 @@ private:
|
||||
nsTArray<nsCOMPtr<nsIDirectoryServiceProvider>> mProviders;
|
||||
|
||||
public:
|
||||
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL(name_)
|
||||
#define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(name_)
|
||||
#include "nsDirectoryServiceAtomList.h"
|
||||
#undef DIR_ATOM
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user